Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: программа на ассемблере
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
dimka76
Добрового времени суток :-)

Хочу написать на ассемблере программку и что-бы она размещалась во внутренней SRAM.
Достаточно ли для этого в начале программы прописать .ORG <адресс SRAM> (естественно после всего того что нужно прописать в стартапе) ?
aaarrr
Вне зависимости от того, на чем написана программа, её размещением будет заниматься линкер. Так что изучайте его документацию.
dimka76
а разве на Си не достаточно перед именем функции написать __famfunc ?
Директива .ORG как раз и говорит линкеру куда размещать следующий за ней код или я не прав?
aaarrr
Цитата(dimka76 @ Jun 4 2008, 16:22) *
а разве на Си не достаточно перед именем функции написать __famfunc ?

"C" - это не только IAR. RVDS, например, вообще не знает что такое __ramfunc.

Цитата(dimka76 @ Jun 4 2008, 16:22) *
Директива .ORG как раз и говорит линкеру куда размещать следующий за ней код или я не прав?

Правильно будет разместить код в определенной секции, а затем указать линкеру, что секция должна быть помещена в область RAM.
Сергей Борщ
Цитата(dimka76 @ Jun 4 2008, 15:22) *
а разве на Си не достаточно перед именем функции написать __famfunc ?
Директива .ORG как раз и говорит линкеру куда размещать следующий за ней код или я не прав?
Рассуждать бессмысленно не зная ни типа процессора ни используемого компилятора/ассемблера/линкера. Обычно директива .ORG задает смещение в текущей секции (а не абсолютный адрес). Адреса начала секций указываются линкеру в его скрипте. __ramfunc, если речь идет об IAR для ARM, указывает линковать код в секцию CODE_I. Скрипт линкера заставляет размещать содержимое секции CODE_I в секцию CODE_ID. Копирование из CODE_ID в CODE_I производит startup-код.

Давайте вы для начала признаетесь, о каком компиляторе/ассемблере идет речь и для какого процессора, а еще уточните, как ваша ассемблерная программа будет попадать в ОЗУ.
dimka76
Цитата(Сергей Борщ @ Jun 5 2008, 13:13) *
Давайте вы для начала признаетесь, о каком компиляторе/ассемблере идет речь и для какого процессора, а еще уточните, как ваша ассемблерная программа будет попадать в ОЗУ.


компилятор IAR C/C++ Compiler for ARM 4.41A Kickstart (4.41.1.301)

процессор LPC2103

При функции написании на Си с указанием __ramfunc функция размещается в ОЗУ, а попадает туда при вкл. питания автоматически копируясь из FLASH. По крайней мере я так понял разбираясь с этим типом контроллеров. Кстати, если писать такие фукции на Си( __ramfunc) -> зашиваю контроллер -> работает (дергает ножкой) -> выключаю питание -> включаю питание -> опять работает -> значит образ функции исполняемой из ОЗУ изначально хранится во FLASH и копируется в ОЗУ при вкл. питания.

Вот я хочу получить такую же функцию на ассемблере, используя IAR.

По поводу директивы .ORG - она задает абсолютный адрес, проверено на практике. И директивы ассемблера, как правило, одинаковы для всех ассемблеров и контроллеров/процессоров. Вот.
Сергей Борщ
Цитата(dimka76 @ Jun 5 2008, 15:58) *
Кстати, если писать такие фукции на Си( __ramfunc) -> зашиваю контроллер -> работает (дергает ножкой) -> выключаю питание -> включаю питание -> опять работает -> значит образ функции исполняемой из ОЗУ изначально хранится во FLASH и копируется в ОЗУ при вкл. питания.
Да. Но это копирование происходит не "само" каким-то магическим образом, а это делает процедура cstartup. Вы можете убедиться в этом, пройдя программу в симуляторе по шагам от вектора сброса до main().
Цитата(dimka76 @ Jun 5 2008, 15:58) *
Вот я хочу получить такую же функцию на ассемблере, используя IAR.
Как отдельную законченную программу или как одну из функций С-программы? Если последнее, то напишите в начале вашей функции
Код
    RSEG CODE_I : CODE
Если как отдельную программу - то вам придется делать копирование самостоятельно.Сложного там ничего нет, обычный цикл, для получения адресов используйте операторы SFB, SFE, в линкерном скрипте - опцию -Q (посмотрите пример в папках компилятора).
Цитата(dimka76 @ Jun 5 2008, 15:58) *
По поводу директивы .ORG - она задает абсолютный адрес, проверено на практике. И директивы ассемблера, как правило, одинаковы для всех ассемблеров и контроллеров/процессоров. Вот.
Вот? Во-первых, "отучаемся говорить за всех...".
Во-вторых, в какой адрес, по-вашему, попадут эти переменные:
Код
        NAME    PWM_Data
        RSEG    PWM_DATA : DATA(0)
        ORG    0

FREQ_0            DS    1
FREQ_1            DS    1
Bitrate            DS    1
/* FFSK */
SinStep            DS    1
Quadrant        DS    1
BitPhase        DS    2
    ORG    SinStep
/* GFSK,GMSK */
Curve            DS    1
Shifter            DS    1
        ENDMOD
Я утверждаю, что в начало сегмента PWM_DATA. А абсолютный адрес присвоит линкер в процессе размещения секции (проверено на практике smile.gif ).

В-третьих: По умолчанию ассемблерный файл ассемблируется в абсолютную секцию (см. директиву ASEG). Поэтому если вы не использовали директив переключения секций (RSEG, ASEG, COMMON, STACK), то ваш код попадал в абсолютную секцию, которая начинается с адреса 0 и поэтому результат вашей ORG совпадал с абсолютным адресом.
dimka76
Цитата(Сергей Борщ @ Jun 5 2008, 16:38) *



Спасибо .
Код
    RSEG CODE_I : CODE
помогло :-)

У меня еще один вопросик возник.

пишу так

с Си файле
Код
extern void foo(void);

void main(void)
{
   foo();
   ...
   ....
}


В ассемблерном файле

Код
        MODULE    ?foo         
        PUBLIC  foo        
            
         RSEG CODE_I : CODE      
           CODE32

Table1:     //всего 255 значений
      
       DC32                   0        //0
       DC32        2        //1
       DC32        6        //2
...
...
       DC32        1025        //255

Table2:     //всего 255 значений
      
       DC32                   0        //0
       DC32        20        //1
       DC32        60        //2
...
...
       DC32        4025        //255


foo                  

      mov   R4,#Table1  
      mov   R8,#Table2

       mov   PC,LR

       ENDMOD  
      
      END


компиляция проходит успешно, а линкер выдает следующие ошибки

Код
Error[e18]: Range error, Number out of range
  Where $ = foo + 0x4  [0x40000804]
            in module "?foo" ,
            offset 0x804 in segment part 0, segment CODE_I
  What: foo [0x40000000]
  Allowed range: 0x0 - 0xFF
  Operand: foo [0x40000000]
           in module ?foo ,
           Offset 0x0 in segment part 0, segment CODE_I


я так подозреваю, что это связано со вторым операндом в строках
Код
      mov   R4,#Table1  
      mov   R8,#Table2


Объясните пожалуйста в чем дело?
vet
dimka76, mov не принимает вторым операндом произвольные константы, о чем компилятор и сообщает прямым текстом.
dimka76
поторопился радоваться.

Си файл
Код
extern __ramfunc void foo(void);

UINT data[255] = {1,1,2,3,4,.........,234};
UINT data[255] = {1,2,3,4,....,255};

void main(void)
{
  foo();
}


Фсеемблерный файл
Код
                NAME    ?foo        
    PUBLIC  foo        
                RSEG  CODE_I : CODE  


foo:
              mov   R1,#10
              mov   R2,#20
              mov   PC,LR

      ENDMOD  
      
      END


иду по шагам когда программа переходит к метке foo: смотрю дизассемблер
и там где должна быть ассемблерная строка расположены нули.

в файле линкера ключ -Q вставлен.

во FLASH образ функции foo() имеется (смотрю map файл и дизассемблер), но он не переписывается при старте во ОЗУ.
Сергей Борщ
Цитата(dimka76 @ Jun 6 2008, 12:24) *
Си файл
А текст самой foo - тайна? :-) используйте команду LDR R1, =Table1. Ассемблер сам положит константу с адресом Table1 где-то рядом с этой командой, а саму команду заменит на соответствующий LDR R1, [PC, #N]
Цитата(dimka76 @ Jun 6 2008, 12:24) *
во FLASH образ функции foo() имеется (смотрю map файл и дизассемблер), но он не переписывается при старте во ОЗУ.
А не подключаете ли вы к программе свой cstartup.s79? Если да, то смотрите - есть ли там копирование. Библиотечный стартап копирование выполняет. A!! Есть у них такая штука, как массив в сегменте INITTAB. Его формат следующий:
Код
/* Structure of an element in the segment initialization table
* in segment INITTAB. Used for both zero-initialization and copying. */
typedef struct
{
  long   Size;                  /* Number of bytes to initialize */
  char*  Dst;                   /* Destination. If Dst==Src, then init to 0 */
  char*  Src;                   /* Source address. Usually in ROM. */
} InitBlock_Type;
А дальше библиотечная функция __segment_init(), проходя по этому массиву, делает копирование:
Код
pragma location="ICODE"
__interwork void __segment_init(void)
{
  InitBlock_Type const * const initTableBegin = __sfb( "INITTAB" );
  InitBlock_Type const * const initTableEnd = __sfe( "INITTAB" );
  InitBlock_Type const * initTableP;

  /* Loop over all elements in the initialization table. */
  for (initTableP=initTableBegin; initTableP<initTableEnd; initTableP++)
  {
    /* If src=dest then we should clear a memory
     * block, otherwise it's a copy operation. */
    if (initTableP->Src == initTableP->Dst)
    {
      memset(initTableP->Dst, 0, initTableP->Size);
    }
    else
    {
      memcpy(initTableP->Dst, initTableP->Src, initTableP->Size);
    }
  }
}
Значит, в вашем ассемблерном файле, вам надо сделать
Код
    RSEG INITTAB:CODE
    dw  .....
    dw  .....
    dw  .....
Вот только сразу не соображу - как взять адрес, откуда копировать. Компилятор как-то подставляет, а как тут сделать - ума не приложу. Вот есть кое-что на сайте самого ИАРа. А вот это как раз подходит под ваш случай. Придется заводить свои сегменты sad.gif В gcc это сделано более оптимально, без массива.
dimka76
спасибо сергею за подсказки

у меня что-то получилось, по крайней мере работает.
привожу код который у меня получился

в проекте три файла
1. main.c

Код
#include <iolpc2103.h>

typedef unsigned int  UINT;
typedef unsigned short  USHORT;
typedef unsigned char UCHAR;

extern __ramfunc void __haffman(USHORT*  pHaff, USHORT* pHaffLen);

USHORT haffman[256] =
{
  0    ,    //0
2    ,    //1
6    ,    //2
...
32766    ,    //254
32767        //255

};

USHORT haffman_len_mask[256] =
{
0x0001    ,    //0
0x0002    ,    //1
...
0x4000        //255
};

USHORT* pHaff = haffman;
USHORT* pHaffMask = haffman_len_mask;

extern void _cpy(void);

void main()
{

  _cpy();
   __haffman(pHaff, pHaffMask);
  
  while(1){}
}


второй сама функция, которая должна выполняться в ОЗУ
2 haff.s79
Код
       MODULE    ?HAFFMAN
      
       RSEG     RAM_FUNC : CODE
        
       PUBLIC  __haffman        
       CODE32
      
       DC32  SFB(RAM_FUNC)
       DC32  SIZEOF(RAM_FUNC)      
        
__haffman:  
     //в R0 указатель на первый входной параметр функции
     // в данном случае указатель на таблицу констант хаффмана
    
     // в R1 указатель на второй входной параметр функции    
     // в данном случае указатель на таблицу длинн констант хаффмана
    
      mov   R2, #35       // data in  
      
      mov   R3,#0x01      // bit position
      
      mov   R10,#0x40000000  // адресс выходных данных
      orr   R10,R10,#0x1000
      mov   R11,#0
      str   R11,[R10]  
      
      mov   R11,#0xFF
      orr   R11,R11,R11, LSL #8  //R11 <- 0x0000FFFF      
      
repeat:  
      ldr  R4,[R0,R2, LSL #1]  //загрузить в R4 код HAFFMAN соответствующий входным данным
      
      orr   R4,R4,R5,LSL #8
      
      and   R4,R4,R11           // маскирование старших 16 бит
      
      mul  R5,R4,R3          // сдвигаем очередной код на текущую позицию
      
      ldr   R9,[R10]     // загружаем выходные данные из текущей позиции
      
      orr   R5,R5,R9    // добавляем новые данные
      
      str   R5,[R0]       // сохраняем новые данные
            
      cmp   R6,#0
      addne R0,R0,#4  
      
      ldr   R7,[R8,R2, LSL #1] //загрузить в R7 длину кода HAFFMAN соответствующий входным данным      
      
      LSL   R7,R7,#1
      
      muls  R5,R3,R7
      
      movcs R3, #0x01
      movcc R3,R5
      
      addcs R0,R0,#8
      
      b     repeat
      
      mov   PC,LR    //возврат из подпрограммы R15 (PC)- программный счетчих,
                        // R14 (LR) - регистр связи в нем автоматически сохраняется
                        // адрес возврата из подпрограммы  
      
      ENDMOD      
      END


и третий файл функция копирования из FLASH в ОЗУ

3 copyd_.s79
Код
      MODULE    ?CPY
      RSEG    CODE_ID : CODE
      PUBLIC    _cpy
      EXTERN    COPYD      
      CODE32
      
_cpy:  
       ldr     R0,COPYD        
       add     R5,R0,#4      
       ldr     R1,[R5],#+4        
       ldr     R2,[R5]
       sub     R2,R2,#1
       add     R0,R0,#4
      
_cpy_1:  ldrb    R12,[R0],#+1
         subs    R2,R2,#1
         strb    R12,[R1],#+1
         bne    _cpy_1
        
         mov   PC,LR          

      ENDMOD  
      
      MODULE    ?FLASH
      RSEG    FLASH :CODE      
      PUBLIC    COPYD        
      CODE32
      
COPYD:       DC32 SFB(FLASH)

      LTORG
      ENDMOD //?FLASH      
      END


и еще подправил файл ххх.XCL
в нем убрал
Код
-QCODE_I=CODE_ID

и добавил
Код
-Z(CODE)RAM_FUNC=40000000-40002000
-Z(CODE)FLASH=40-7FFF

-QRAM_FUNC=FLASH


может получилось несколько коряво, но симуляция показывает, что принцип работает.
сама функция
Код
void __haffman(USHORT*  pHaff, USHORT* pHaffLen);
сырая. я над ней еще работаю поэтому прошу не обращать особого внимания на ее тело

а весь проект целиком в прикрепленном файле

идея реализации алгоритма Хаффмана взята в подфоруме AVR (необычное использование аппаратного умножителя)
aaarrr
Еще регистры R4-R11 сохранять надо, если планируется вызов из "C".
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.