Something SPECIAL: put variables anywhere

MPC | |

Byte Craft Limited's compilers support SPECIAL memory: user-declared memory blocks accessed (read and written) by software. The compiler manages allocation for SPECIAL memory similarly to system RAM and ROM. The result is a seamless integration of off-chip or on-chip memory resources into C language programs. Even persistent memory can host C language variables.

This is an example showing two different ways to access EEPROM: by library functions and through SPECIAL memory variables. Both methods ultimately use the same library functions.

First, we declare the library routines and related macros that drive the EEPROM in both cases:

                                  //EEPROM functionality
000C                              #define Enable_EE_WR       EECON1.WREN = 1
000D                              #define Disable_EE_WR      EECON1.WREN = 0
000E                              #define EEProm_Rd          EECON1.EERD   = 1
000F                              #define Do_EE_Write        #asm( BSF 0x08,1)
0010                              #define EEProm_Writing     EECON1.EEWR

                                  //EEPROM API
                                  int Read_EEProm(registerw addr);
                                  void Write_EEProm(registerx addr, registerw data);

Next, we link the compiler's variable allocation system with the library routines through a SPECIAL declaration. SPECIAL expects two routines to be declared with names based on the "eeprom" area name.

                                  //SPECIAL MEMORY DECLARATION
0000 003F                         #pragma memory SPECIAL eeprom [0x3F] @ 0x00;
                                  //required identifier to point to API functions
0011                              #define eeprom_r Read_EEProm
                                  //recreates write described below
0012                              #define eeprom_w(addr,data) \
                                   {Write_EEProm(addr,data); while(EEProm_Writing); Disable_EE_WR;}


                                  //SPECIAL VARIABLE DECLARATIONS
0000 0001                         char eeprom a,b;

The program begins with traditional, function-based access:


                                  void main()
                                  {
004F 004E                           unsigned int addr, data;

0005 3018    MOVLW  18h             data = 0x18;   // Data to be written/read
0006 00CE    MOVWF  4E
0007 01CF    CLRF   4F              addr = 0x00;   // Address to write to

                                  //-------------- EEPROM  WRITE ----------------
0008 084F    MOVF   4F,W            Write_EEProm(addr,data);
0009 0084    MOVWF  FSR
000A 084E    MOVF   4E,W
000B 2037    CALL   0037h
000C 1683    BSF    STATUS,RP0      while(EEProm_Writing);  // Wait till data written
000D 1888    BTFSC  88,1
000E 280C    GOTO   000Ch
000F 1108    BCF    88,2            Disable_EE_WR;     // Good practice if no more writes

                                  //--------------- EEPROM READ -----------------
0010 084F    MOVF   4F,W            data = Read_EEProm(addr);  // Read data back from EEPROM
0011 2030    CALL   0030h
0012 00CE    MOVWF  4E

0013 1683    BSF    STATUS,RP0      TRISB = 0x00;
0014 0186    CLRF   86
0015 1283    BCF    STATUS,RP0      PORTB = data;      // Port B is connected to LEDs
0016 0086    MOVWF  PORTB

Compare this with access through SPECIAL variables, declared above:


                                  //------------- EEPROM READ through SPECIAL ---
0017 3000    MOVLW  00h             PORTB = a;
0018 2030    CALL   0030h
0019 1283    BCF    STATUS,RP0
001A 0086    MOVWF  PORTB
001B 3001    MOVLW  01h             PORTB = b;
001C 2030    CALL   0030h
001D 1283    BCF    STATUS,RP0
001E 0086    MOVWF  PORTB

                                  //------------- EEPROM WRITE through SPECIAL --
001F 0184    CLRF   FSR             a = 23;
0020 3017    MOVLW  17h
0021 2037    CALL   0037h
0022 1683    BSF    STATUS,RP0
0023 1888    BTFSC  88,1
0024 2822    GOTO   0022h
0025 1108    BCF    88,2
0026 3001    MOVLW  01h             b = PORTB;
0027 0084    MOVWF  FSR
0028 1283    BCF    STATUS,RP0
0029 0806    MOVF   PORTB,W
002A 2037    CALL   0037h
002B 1683    BSF    STATUS,RP0
002C 1888    BTFSC  88,1
002D 282B    GOTO   002Bh
002E 1108    BCF    88,2

                                  } // main()

And finally, the EEPROM library routines themselves:



                                  ///////////////////////////////////////////////////

                                  int Read_EEProm(registerw addr)
0000                              {
0030 1283    BCF    STATUS,RP0      EEADR = addr;
0031 0089    MOVWF  EEADR
0032 1683    BSF    STATUS,RP0      EEProm_Rd;
0033 1408    BSF    88,0
0034 1283    BCF    STATUS,RP0      return(EEDATA);
0035 0808    MOVF   EEDATA,W
0036 0008    RETURN 
                                  }

                                  ///////////////////////////////////////////////////

                                  void Write_EEProm(registerx addr, registerw data)
0000 0000                         {
0037 1683    BSF    STATUS,RP0      Enable_EE_WR;
0038 1508    BSF    88,2
0039 1283    BCF    STATUS,RP0      EEDATA = data;
003A 0088    MOVWF  EEDATA
003B 0804    MOVF   FSR,W           EEADR = addr;
003C 0089    MOVWF  EEADR
003D 1683    BSF    STATUS,RP0      STATUS.RP0 = 1;
003E 138B    BCF    INTCON,GIE      INTCON.GIE=0;
                                  #asm
003F 3055                 MOVLW  55H  ;Sequence must be coded exactly
0040 0089                 MOVWF  09   ;as shown according to data book.
0041 30AA                 MOVLW  0AAh
0042 0089                 MOVWF  09
                                  #endasm
0043 1488    BSF    EEDATA,1        Do_EE_Write;
0044 178B    BSF    INTCON,GIE      INTCON.GIE = 1;
0045 0008    RETURN               }

The SPECIAL variables even show up in the symbol table; when you have a lot of them, this information helps in debugging.

SYMBOL TABLE

LABEL                             VALUE LABEL                             VALUE 

a                                0000 | b                                0001 

SPECIAL memory makes for cleaner, more intuitive code. After the read and write driver routines are added, each new variable requires only a declaration.

SPECIAL memory will in time give way to _Access memory. Byte Craft Limited participates in ISO/IEC WG 14, the group responsible for evolving the C language international standard. Our experience with SPECIAL helped inform ISO/IEC TR 18037, the technical report that extends C with embedded-specific functionality. _Access declarations are similar to SPECIAL in almost all respects.