How is Data stored in ROM?

Discussion in 'Embedded Systems and Microcontrollers' started by JerryNa, Feb 3, 2014.

  1. JerryNa

    Thread Starter Member

    Feb 15, 2010
    Say that you got the following Code that was burnt into ROM of a DSP Processor:

    Code ( (Unknown Language)):
    1. #include <stdio.h>
    3. int globvar;
    5. int main()
    6. {
    7. int localvar = 5;
    9. scanf("%i, &globvar);
    11. localvar = globvar + 5;
    13. printf("Sum of Global and Local is: %i", globvar+localvar);
    15. return 0;
    16. }

    How would localvar and globvar be placed in ROM?

    for example, will the ROM include for each:
    for globvar:
    - Address in Static Area of RAM
    - Size

    for localvar:
    - Address in RAM (Stack)
    - Size
    - - - Is localvar's memory address in RAM determined on run time?

    Thank you.
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    The job of the compiler is to put the code you write into code the processor understands. In this case, the compiler will allocate memory for your variable and reference the address as is consistent with your definition. The compiled code will have no knowledge of what a localvar is, just that there is a section of memory that is equal to the data stored in another address (the memory location of the globalvar variable) plus 5.
  3. MrChips


    Oct 2, 2009

    globvar is an address in Static area of RAM.
    localvar is an address in RAM taken from the stack area.
    localvar is dynamically allocated at run time when the subroutine is called. The address is assigned depending on what the SP (Stack Pointer is currently pointing to).
  4. takao21203

    Distinguished Member

    Apr 28, 2012
    Depends on the controller.
    For RAM, the compiler will place statements which use address registers.
    For ROM, the compiler will generate ROM access sequences specific to the chip.
    Some can access the ROM just by setting up the right address.
    Others need to set special registers before reading from ROM.

    On the other hand, the ROM with the program code indeed will contain references to the RAM address each time when it is accessed. You can see such a thing via disassembly- highly educational!

    The size is determined by the controller chipset.
    8 bit chips use ssequences of instructions to emulate larger sizes in software.
    Larger controllers indeed have different opcodes for different operand sizes.

    Thats the big advantage of C language for controllers- you can almost stop bothering about the memory layout, and you can port software. If you use assembler, and rely on some special addressing mode, you are locked to that chip.

    On the other hand, if you use certain addressing in C and there is no supporting instruction in assembler, the resulting code may be very slow- not just the usual C language trade off but really really totally slow.

    With that knowledge, you should be careful with array addressing, and complex addressing constructs, if they are not supported directly.

    If you repeat them a few times it might be most of the small ROM becomes used up just for that.

    Some fundamental knowledge of how the controller deals with it's memories is important to write a well performing C program.

    Also each controller is a bit different- some for instance can execute from RAM, while others can not even read the ROM directly at all.
  5. JerryNa

    Thread Starter Member

    Feb 15, 2010

    Thank you MrChips and tshuck and takao!

    If it's OK, I'd like to make it clear:

    1. Is it correct to say that the ROM Includes the :
    a. RAM Address of globvar ?
    b. Size of globvar (e.g. 4 bytes) ?

    2. if localvar is allocated dynamically with a RAM Address, How exactly is localvar represented in ROM?

    Thank you.
  6. takao21203

    Distinguished Member

    Apr 28, 2012
    The PIC baseline for instance is using this for addressing a variable (they dont store variables on the stack).

    movlw LOW(&localvar)
    movwf FSR
    movf INDF,W

    each of these 3 lines will become one 12bit word in the ROM, a so-called opcode. &localvar is a constant value by the way.

    1. load address low bits as literal into accumulator
    2. store accumulator into File Select Register
    3. load file register content (Indirect F) into W (accumulator)

    A C compiler will also set banking bits (for instance).

    As said, for a proper understanding, write some C statements, compile, and examine the disassembly.

    A RAM space is not to be said as being represented in ROM.

    The ROM of course contains the program opcodes as such, and they are somehow representing RAM areas.

    However, it is said that a RAM address is accessed with an indexing instruction. Typically this would be some kind of MOV instruction. For different purposes, there are various addressing modes.

    The question which addressing mode is used and why is well important to deal with. You have to skip through a lot of materials to get a grip on all the terminology.

    Asking questions on forums also helps.

    But really the ROM is said to hold a representation of the program code. In a linker script for instance you sometimes really represent RAM areas, or better you write the definition rules for them.

    C compilers also have statements to control the allocation into ROM sections.

    What the ROM in the end will contain are opcodes, some of them using one of the addressing modes to load/store from/to RAM, and some controllers also directly read from the ROM.

    The ROM is nowadays normally known as the "FLASH", but ROM is technically correct to use.

    2. About the dynamic allocation. Not all controllers use a stack. If they do, instead of sequences for ROM there will be sequences to access the stack. Some controllers have a special register, a stack pointer.
    Last edited: Feb 3, 2014
  7. tshuck

    Well-Known Member

    Oct 18, 2012
    Because no data is being modified, the compiler could determine that the data used in your program is static and ,therefore, use values stored in ROM.

    Assuming the value of globalvar is assigned previously (at compile time), the compiler would determine if the value is changed at any point. If it isn't, as is the case here, the compiler would probably use the value within the program data(ROM).

    If, however, gobalvar was modified in the program, a location in RAM would be allocated by the compiler and the program would reference the data at the location in RAM corresponding to globalvar.

    Localvar's implementation depends on how globalvar's implemented.

    In short, the compiler will decide on how and what to do with variables depending on usage, compiler settings, and the compiler itself.
  8. tshuck

    Well-Known Member

    Oct 18, 2012
    No, ROM means Read Only Memory. In the case of Flash memory in PICs, it can be overwritten during operation, meaning the memory is read/write memory.

    The correct term is "program memory".
  9. MrChips


    Oct 2, 2009
    As takao says it depends on the processor and compiler. If we assume that we are using a small microcontroller then we can make the following assumptions:

    1. The address of the globvar is hard coded in the ROM code.
    The size of the globvar is not recorded. Its size is implicit in the code generated.

    2. The location of a local variable is hard coded in ROM code as an offset with respect to the current address in the SP (stack pointer).
  10. takao21203

    Distinguished Member

    Apr 28, 2012
    Yes most PICs used for new designs can reprogram the FLASH (even if many applications will not have facilities or a need to do so).

    If you examine the datasheets, one calls it FLASH, while a more recent one is using the term Program Flash Memory.

    2 I think the question as such is fundamental. Once you understand about it, you can write more advanced programs, but otherwise you are limited to repeat some C spellings from a book or tutorial.

    This is how I used C in the first time.

    Datasheets don't often contain a glossarry or small tutorial, and from what I know about software books, useful bits and pieces are distributed over 20 different books, with many chapters not useful at all.

    Consider for instance this`C source.
    Especially the way I setup TRIS registers from a pin table, and also I spell a constant to specify the PORT and the bit number.

    without a proper understandings how these "representations" do occur, I would not be able to code such things in C.

    Code ( (Unknown Language)):
    2. unsigned char v_PORTA,v_PORTB,v_PORTC,v_PORTD,v_PORTE;
    3. unsigned char v_TRISA,v_TRISB,v_TRISC,v_TRISD,v_TRISE;
    5. unsigned char disp_digits[]={0,0,0};
    7. unsigned int v_disp_data;
    8. unsigned char v_disp_upd;
    9. #define c_disp_upd_delay 0x08
    11. const unsigned char disp_data_shift[]={0,4,8};
    13. unsigned char v_phase,v_led0;
    14. #define c_led0_delay 0x30
    16. #define c_digits 7
    17. #define c_anodes 2
    19. const unsigned char led7seg_data[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x47,\
    20.                                     0x7f,0x67,0x77,0x7c,0x39,0x5e,0x79,0x71,\
    21.                                     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
    22.                                     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    24. #define v_PORTA_idx 0
    25. #define v_PORTB_idx 1
    26. #define v_PORTC_idx 2
    27. #define v_PORTD_idx 3
    28. #define v_PORTE_idx 4
    30. #define c_nphases 3
    32. const unsigned char* portvars[]={&v_PORTA,&v_PORTB,&v_PORTC,&v_PORTD,&v_PORTE};
    34. const unsigned char* trisvars[]={&TRISA,&TRISB,&TRISC,&TRISD,&TRISE};
    36. const unsigned char led7seg_decode[]={v_PORTD_idx,6,\
    38.                            v_PORTB_idx,3,\
    39.                            v_PORTA_idx,5,\
    40.                            v_PORTE_idx,1,\
    41.                            v_PORTE_idx,2,\
    42.                            v_PORTD_idx,7,\
    43.                            v_PORTA_idx,4,\
    44.                            v_PORTE_idx,0};
    46. const unsigned char led7seg_anodes[]={v_PORTD_idx,5,\
    47.                              v_PORTB_idx,1,\
    48.                              v_PORTB_idx,2};
    50. // OR - set to 1
    51. const unsigned char led7seg_decode_reset2[]={1,2,4,8,16,32,64,128};
    52. // AND - set to 0
    53. const unsigned char led7seg_decode_set2[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
    55. const unsigned char led7seg_phase_patts[]={0b00000100,0b00000010,0b00000001};
    57. void configure_TRIS()
    58. {unsigned char i,i2,v_port,v_portbit,v_trisdata;
    59. unsigned char* v_trisvar;
    61.  for(i=0;i<=c_digits;i++)
    62.  {
    63.      i2=i<<1;
    64.      v_port=led7seg_decode[i2];
    65.      v_trisvar=trisvars[v_port];
    66.      v_trisdata=*v_trisvar;
    67.      v_portbit=led7seg_decode[i2+1];
    69.      v_trisdata&=led7seg_decode_set2[v_portbit];
    70.      *v_trisvar=v_trisdata;
    71.  }
    73.  for(i=0;i<=c_anodes;i++)
    74.  {
    75.      i2=i<<1;
    76.      v_port=led7seg_anodes[i2];
    77.      v_trisvar=trisvars[v_port];
    78.      v_trisdata=*v_trisvar;
    79.      v_portbit=led7seg_anodes[i2+1];
    81.      v_trisdata&=led7seg_decode_set2[v_portbit];
    82.      *v_trisvar=v_trisdata;
    83.  }
    84. }
    86. void refresh_anodes(unsigned char v_phase)
    87. {unsigned char v_phase_patt;
    88.  unsigned char i,i2,shl_data,port,portbit,portdata;
    89.  unsigned char* portvar;
    91.  shl_data=1;
    92.  v_phase_patt=led7seg_phase_patts[v_phase];
    93.  for(i=0;i<=c_anodes;i++)
    94.  {
    95.      i2=i<<1;
    96.      port=led7seg_anodes[i2];
    97.      portvar=portvars[port];
    98.      portbit=led7seg_anodes[i2+1];
    99.      portdata=*portvar;
    101.      if(shl_data&v_phase_patt)
    102.      {
    103.       portdata|=led7seg_decode_reset2[portbit];
    104.      }else
    105.      {
    106.       portdata&=led7seg_decode_set2[portbit];
    107.      }
    108.      *portvar=portdata;
    109.      shl_data<<=1;
    110.  }
    112. }
    114. void refresh_digits(unsigned char v_phase)
    115. {unsigned char shl_val,disp_data_patt,disp_data;
    116. unsigned char i,i2,port,port_data,portbit;
    117. unsigned char* portvar;
    119. disp_data=disp_digits[v_phase];
    120. disp_data&=0x1f;
    121. disp_data_patt=led7seg_data[disp_data];
    123.  shl_val=1;
    124.  for(i=0;i<=c_digits;i++)
    125.  {
    126.   i2=i<<1;
    127.   port=led7seg_decode[i2];
    128.   portvar=portvars[port];
    129.   port_data=*portvar;
    130.   portbit=led7seg_decode[i2+1];
    132.   if(shl_val&disp_data_patt)
    133.   {
    134.    port_data&=led7seg_decode_set2[portbit];
    135.   }else
    136.   {
    137.    port_data|=led7seg_decode_reset2[portbit];
    138.   }
    139.   *portvar=port_data;
    140.   shl_val<<=1;
    141.  }
    142. }
    144. void update_digits(unsigned int v_data)
    145. {
    146.     disp_digits[0]=(unsigned char)(v_data&0x0f);
    147.     disp_digits[1]=(unsigned char)((v_data>>4)&0x0f);
    148.     disp_digits[2]=(unsigned char)((v_data>>8)&0x0f);
    149. }
    150. /* i.e. uint8_t <variable_name>; */
    152. /******************************************************************************/
    153. /* Main Program                                                               */
    154. /******************************************************************************/
    155. void main(void)
    156. {
    157.     /* Configure the oscillator for the device */
    158.     ConfigureOscillator();
    160.     /* Initialize I/O and Peripherals for application */
    161.     configure_TRIS();
    163.     InitApp();
    164.     v_phase=0;
    165.     v_led0=0;
    166.     v_disp_data=0;
    167.     v_disp_upd=0;
    168.     update_digits(v_disp_data);
    170.     while(1)
    171.     {
    172.         if(v_flags&c_flags_timer0_set)
    173.         {
    174.             v_flags&=c_flags_timer0_reset;
    176.             refresh_digits(v_phase);
    177.             refresh_anodes(v_phase);
    179.             v_phase++;if(v_phase==c_nphases){v_phase=0;}
    181.             v_disp_upd++;if(v_disp_upd==c_disp_upd_delay)
    182.             {
    183.                 v_disp_upd=0;
    184.                 v_disp_data++;
    185.                 if(v_disp_data==0xfff)
    186.                 {
    187.                     v_disp_data=0;
    188.                 }
    189.                 update_digits(v_disp_data);
    190.             }
    191.             v_led0++;if(v_led0==c_led0_delay)
    192.             {
    193.                 v_led0=0;
    194.                 if(v_flags&c_flags_led0_set)
    195.                 {
    196.                  v_flags&=c_flags_led0_reset;
    197.                  v_PORTC&=c_flags_led0_reset;
    198.                 }else
    199.                 {
    200.                  v_flags|=c_flags_led0_set;
    201.                  v_PORTC|=c_flags_led0_set;
    202.                 }
    203.             }
    204.         PORTA=v_PORTA;
    205.         PORTB=v_PORTB;
    206.         PORTC=v_PORTC;
    207.         PORTD=v_PORTD;
    208.         PORTE=v_PORTE;
    209.         }
    211.     }
    212. }