Перейти к содержанию
    

Keil 9+Silabs C51+pdata

Всем, привет!

Делаю первый проект на С для С51.

Возникла следующая проблема.

При использовании модели памяти compact не удается определить местоположение стека.

То есть при вызове reentrant функции портятся переменные расположенные в памяти xdata по адресу меньше 0x100.

Проверил все опции, прочитал хелп, пользовался поиском - не могу найти решения проблемы.

Подскажите кто знает как исправить проблему.

Заранее спасибо!

 

Линкер генерит такую таблицу памяти

 

ACTIVE MEMORY CLASSES OF MODULE: msd-silabs (F34X_MSD_USB_MAIN)

 

BASE START END USED MEMORY CLASS

==========================================================

X:000000H X:000000H X:000FFFH 000CECH XDATA

X:000000H X:000000H X:000FFFH HDATA

C:000000H C:000000H C:00FFFFH ECODE

B00:0000H C:000000H C:00FFFFH HCONST

C:000000H C:000000H C:00FFFFH 008E13H CODE

X:000000H X:000000H X:0000FFH 0000B7H PDATA

I:000000H I:000000H I:00007FH 000046H DATA

C:000000H C:000000H C:00FFFFH 000131H CONST

I:000000H I:000000H I:0000FFH 000080H IDATA

 

Изменено пользователем 1kvi1

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Определение:

The COMPACT Directive selects the compact memory model, in which all function and procedure variables and local segments reside in the external data memory of the 8051 system.

 

Обратите внимание на - "in which all .... reside in the EXTERNAL DATA MEMORY".

.....

То есть при заявленных X:000FFFH 000CECH XDATA, дополнительно под все Ваши локальные переменные, загружаемые константы, а так же стек, скорее всего просто не хватает памяти.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

0000B7H PDATA + 000CECH XDATA

Памяти хватает, проблема в том что указатель программного стека не инициализируется на вершину.

Инициализироваться он должен в стартап коде, но его местоположение заранее не известно.

Как узнать адрес и размер программного стека или как заставить линкер самому вычислять?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На самом деле не совсем так. Судя по таблице линкера 0000B7H PDATA + 000CECH XDATA + 000FFFH HDATA. Стек то ведь то же туда же укладывается.

Посмотрите в симуляторе, что пишется в регистр SP. Можно так же "покрутить" программу и посмотреть значение SP_max. Впрочем можно посмотреть эти значения и в листинге, если он генерируется.

Потом изменить модель памяти на LARGE и посмотреть все те же значения.

Уверяю Вас, все строго определено и ни компайлер ни линкер каких либо вольностей себе не позволяют.

 

Несколько лет назад переживал примерно похожий "кризис веры в Keil", пока не обнаружил, что в одной из моих процедур маска ограничивающая размер буфера была по ошибке выбрана больше размера самого буфера на целый разряд.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всем, привет!

Делаю первый проект на С для С51.

Возникла следующая проблема.

При использовании модели памяти compact не удается определить местоположение стека.

То есть при вызове reentrant функции портятся переменные расположенные в памяти xdata по адресу меньше 0x100.

 

Добрый день.

В стартап файле есть поля инициализации программного стека (в частности и для перевызываемых функций).

 

Вот кусок из моего стартапа

;------------------------------------------------------------------------------
;
;  Reentrant Stack Initilization
;
;  The following EQU statements define the stack pointer for reentrant
;  functions and initialized it:
;
;  Stack Space for reentrant functions in the SMALL model.
IBPSTACK    EQU    1; set to 1 if small reentrant is used.
IBPSTACKTOP    EQU    0FFH+1; set top of stack to highest location+1.
;
;  Stack Space for reentrant functions in the LARGE model.    
XBPSTACK    EQU    1; set to 1 if large reentrant is used.
XBPSTACKTOP    EQU    0FFFFH+1; set top of stack to highest location+1.
;
;  Stack Space for reentrant functions in the COMPACT model.    
PBPSTACK    EQU    1; set to 1 if compact reentrant is used.
PBPSTACKTOP    EQU    0FFFFH+1; set top of stack to highest location+1.
;
;------------------------------------------------------------------------------

 

Удачи

Изменено пользователем AndreyS

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Старт-ап код я исправил и указал вершину на 0x100. Я так понимаю линкер должен это учесть и не располагать переменые и структуры ниже адреса 0x100? Но он так не делает и игнорирует. Сейчас после каждой компиляции проверяю по листингу с какого адреса лежат переменные и в стартапе устанавливаю соответствующее значение.

 

Кроме того ассемблерная инструкция - совсем не указание линкеру освободить данную область памяти?

 

Как решить проблему?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот получается такая таблица памяти. В старт-апе установлена вершина PDATA стека на 0x100

 

* * * * * * * * * * *  X D A T A   M E M O R Y  * * * * * * * * * * * * *
000000H   000085H   000086H   BYTE   INPAGE   PDATA          _PDATA_GROUP_
000086H   000093H   00000EH   BYTE   INPAGE   PDATA          ?PD?F34X_MSD_USB_ISR
000094H   00009FH   00000CH   BYTE   INPAGE   PDATA          ?PD?F34X_MSD_USB_DESCRIPTOR
0000A0H   0000AAH   00000BH   BYTE   INPAGE   PDATA          ?PD?_FREAD?F34X_MSD_FILE_SYSTEM
0000ABH   0000B0H   000006H   BYTE   INPAGE   PDATA          ?PD?_GET_FILE_NAME?F34X_MSD_FILE_SYSTEM
0000B1H   0000B6H   000006H   BYTE   INPAGE   PDATA          ?PD?_FINDNAME?F34X_MSD_FILE_SYSTEM
0000B7H   0000B9H   000003H   BYTE   INPAGE   PDATA          ?PD?_WAVPLAY_INIT?F34X_MSD_USB_MAIN
0000BAH   000303H   00024AH   BYTE   UNIT     XDATA          ?XD?F34X_MSD_NF_BASIC_FUNCTIONS
000304H   000514H   000211H   BYTE   UNIT     XDATA          ?XD?F34X_MSD_SECT_SERV
000515H   000658H   000144H   BYTE   UNIT     XDATA          ?XD?F34X_MSD_USB_MAIN
000659H   0006E0H   000088H   BYTE   UNIT     XDATA          ?XD?F34X_MSD_USB_ISR
0006E1H   00072EH   00004EH   BYTE   UNIT     XDATA          ?XD?F34X_MSD_FILE_SYSTEM
00072FH   00075BH   00002DH   BYTE   UNIT     XDATA          ?XD?F34X_MSD_MSD
00075CH   00077EH   000023H   BYTE   UNIT     XDATA          _XDATA_GROUP_
00077FH   00078BH   00000DH   BYTE   UNIT     XDATA          ?XD?F34X_MSD_SCSI
00078CH   000791H   000006H   BYTE   UNIT     XDATA          ?XD?_GET_FILE_NAME?F34X_MSD_FILE_SYSTEM
000792H   000796H   000005H   BYTE   UNIT     XDATA          ?XD?_FINDNAME?F34X_MSD_FILE_SYSTEM

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Старт-ап код я исправил и указал вершину на 0x100. Я так понимаю линкер должен это учесть и не располагать переменые и структуры ниже адреса 0x100?

Нет смысла править STARTUP.A51 для этого. Линкер его не анализирует. А располагает все переменные и структуры согласно выбранной модели памяти. Попробуйте установить модель памяти LARGE и увидите совсем другую картину, если конечно в программе нет ошибок.

Что бы убедиться в том где располагается стек, а так же насколько глубоко и куда он "растет", можно попробовать вот такую рекомендацию от Keil-а, - http://www.keil.com/support/docs/192.htm

Если очень хочется проверить работу со стеком не в стимуляторе, а на боевой программе, то можно воспользоваться вот такой рекомендацией, - http://www.keil.com/support/docs/2095.htm.

 

Кроме того ассемблерная инструкция - совсем не указание линкеру освободить данную область памяти?

Совершенно не указ. Если необходимо располагать переменные по абсолютному и заранее известному адресу в RAM, то почитайте вот эту рекомендацию, - http://www.keil.com/support/docs/1455.htm Но такой подход требует повышенной внимательности и аккуратности от программиста.

 

Как решить проблему?

Несколько раз перечитал всю ветку, но так и не понял, что Вы называете проблемой, какое поведение хотите получить, а главное зачем?

Если переменные "забивают" стек, то это либо ошибка (ошибки) в программе, либо неверно выбранная модель памяти. Но в любом случае, танцы с бубном вокруг месторасположения стека этих проблем не решат.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Цитата(1kvi1 @ Mar 19 2011, 06:57) *

Старт-ап код я исправил и указал вершину на 0x100. Я так понимаю линкер должен это учесть и не располагать переменые и структуры ниже адреса 0x100?

 

Нет смысла править STARTUP.A51 для этого. Линкер его не анализирует. А располагает все переменные и структуры согласно выбранной модели памяти. Попробуйте установить модель памяти LARGE и увидите совсем другую картину, если конечно в программе нет ошибок.

 

Поставить модель LARGE я не могу по ряду причин. В программе нет ошибок (связанных с этой ситуацией).

 

Несколько раз перечитал всю ветку, но так и не понял, что Вы называете проблемой, какое поведение хотите получить, а главное зачем?

 

Проблема в следующем - в проекте есть старт-ап код

IF PBPSTACK <> 0
EXTRN DATA (?C_PBP)
                MOV     ?C_PBP,#LOW PBPSTACKTOP
ENDIF

 

Привожу его кусок куда нужно заострить внимание. Согласно документации выставляем PBPSTACK =1 и PBPSTACKTOP=0xFF. Это требуется при использовании модели PDATA.

 

Теперь внимание привожу пример листинга reentrant функции - то есть та которая использует программный (эмулируемый) стек, который как раз согласно модели и должен располагаться в xdata-памяти, в первой странице.

 

   183: IF PBPSTACK <> 0 
   184: EXTRN DATA (?C_PBP) 
C:0x0DC8    755E00   MOV      0x5E,#0x00
   185:                 MOV     ?C_PBP,#LOW PBPSTACKTOP 
   186: ENDIF 
   187:  
C:0x0DCB    75607C   MOV      0x60,#Data_Ptr(0x7C)
   188:                 MOV     SP,#?STACK-1 
   189:  
   190:; This code is required if you use L51_BANK.A51 with Banking Mode 4 
   191:;<h> Code Banking 
   192:; <q> Select Bank 0 for L51_BANK.A51 Mode 4 
   193: #if 0    
   194:;     <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.

 

Фрагмент листинга - страт-ап кода - видим что переменная C_PBP куда мы записали вершину стека находится по адресу 0x60.

 

C:0x8C2B    FD       MOV      R5,A
C:0x8C2C    08       INC      R0
C:0x8C2D    E2       MOVX     A,@R0
C:0x8C2E    FE       MOV      R6,A
C:0x8C2F    08       INC      R0
C:0x8C30    E2       MOVX     A,@R0
C:0x8C31    FF       MOV      R7,A
  1814: void SectorRemapUpdateLogPhy (unsigned long log,unsigned long phy) reentrant { 
  1815:         unsigned char c; 
C:0x8C32    E560     MOV      A,0x60
C:0x8C34    24FC     ADD      A,#PCA0CPH0(0xFC)
C:0x8C36    F560     MOV      0x60,A
C:0x8C38    F8       MOV      R0,A
C:0x8C39    1205C6   LCALL    C?LSTPDATA(C:05C6)
C:0x8C3C    E560     MOV      A,0x60
C:0x8C3E    24F4     ADD      A,#P3MDIN(0xF4)
C:0x8C40    F560     MOV      0x60,A
  1816:         unsigned char n=~0; 
C:0x8C42    F8       MOV      R0,A
C:0x8C43    08       INC      R0
C:0x8C44    74FF     MOV      A,#VDM0CN(0xFF)
C:0x8C46    F2       MOVX     @R0,A

 

Собственно reentrunt функция. Использует переменную C_PBP как вершину стека и сохраняет в памяти локальный переменные. Выше указывал что C_PBP указывает на адрес 0xFF, куда линкер (простая душа) положил нужные переменные.

 

* * * * * * * * * * *  X D A T A   M E M O R Y  * * * * * * * * * * * * *
000000H   00007BH   00007CH   BYTE   INPAGE   PDATA          _PDATA_GROUP_
00007CH   000089H   00000EH   BYTE   INPAGE   PDATA          ?PD?F34X_MSD_USB_ISR
00008AH   000095H   00000CH   BYTE   INPAGE   PDATA          ?PD?F34X_MSD_USB_DESCRIPTOR
000096H   0000A0H   00000BH   BYTE   INPAGE   PDATA          ?PD?_FREAD?F34X_MSD_FILE_SYSTEM
0000A1H   0000A6H   000006H   BYTE   INPAGE   PDATA          ?PD?_GET_FILE_NAME?F34X_MSD_FILE_SYSTEM
0000A7H   0000ACH   000006H   BYTE   INPAGE   PDATA          ?PD?_FINDNAME?F34X_MSD_FILE_SYSTEM
0000ADH   0000AFH   000003H   BYTE   INPAGE   PDATA          ?PD?_WAVPLAY_INIT?F34X_MSD_USB_MAIN
0000B0H   0003C8H   000319H   BYTE   UNIT     XDATA          ?XD?F34X_MSD_NF_BASIC_FUNCTIONS
0003C9H   0005D9H   000211H   BYTE   UNIT     XDATA          ?XD?F34X_MSD_SECT_SERV

 

Вот такая неприятная ситуация - сейчас занимаюсь тем что смотрю в листинге адрес _PDATA_GROUP_ и подставляю в старт-ап код соответствующее значение - тогда работает. Число 0x7b - адрес вершины стека согласно листингу.

; <h> Stack Space for reentrant functions in the COMPACT model.    
;  <q> PBPSTACK: Enable COMPACT model reentrant stack
;     <i> Stack space for reentrant functions in the COMPACT model.
PBPSTACK        EQU     1      ; set to 1 if compact reentrant is used.
;
;   <o> PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF>
;     <i> Set the top of the stack to the highest location.
PBPSTACKTOP     EQU     0x7B+1    ; default 0FFH+1  
; </h>
;</h>

 

Ну вот собственно вопрос - почему среда сама не ставит адрес вершины стека и как оптимизировать этот процесс. Я не так хорошо знаком с keil'ом как например с iar'ом (последний явно совершенней). Просьба напишите как сделать правильно - очень не хочется переносить проект под другую среду.

 

Заранее спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну вот собственно вопрос - почему среда сама не ставит адрес вершины стека и как оптимизировать этот процесс. Я не так хорошо знаком с keil'ом как например с iar'ом (последний явно совершенней). Просьба напишите как сделать правильно - очень не хочется переносить проект под другую среду.

 

Теперь понятно

Покрутил в симуляторе свои reentrant функции, в последнее время я крайне редко их применяю. Действительно, нет у Keil-a возможности автоматического определения вершину стека.

Вот что пашет Keil по этому поводу.

PBPSTACKTOP:

Specifies the top of the small model reentrant stack. The default is 0xFF in idata memory.

The Cx51 Compiler does not check to see if the stack area available satisfies the requirements of the application. It is your responsibility to perform such a test.

 

Получается, что Вы можете либо использовать другой компайлер, либо переработать проект и избавиться от reentrant функций, либо после каждой компиляции править руками STARTUP.

Хотел помочь, но увы :(

Изменено пользователем O.L.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Очень жалко, что ответа найти не удается.

Проблема в том что я не знаю какую именно цифру ставить как вершину стека.

Вот если посмотреть листинг линкера - какой алгоритм выбора вершины?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добрый день.

 

Странный код у вас при вызове перевызываемой функции. Вот пример моей функции и ее листинг

 

Вот сама процедура на Си (первые цифры - это номера строк в коде, что бы легче было произвести сравнение с листингом)

На отсутствие return не смотрите.

 

330 bit set_CS(byte set) reentrant
331 {
332     if (SPI_mas.ptrs[SPI_mas.rd].type==SPI_SD_card)
333     {// CS для карты памяти
334         CS_SD_card=(bit)set;
335         return(CS_SD_card);
336    }
337 }

 

Вот листинг. Тут видно что программный стек идет вниз (аппаратный идет вверх, SP. Вверх - к старшим адресам) из этого прямой вывод, что ставить начальный адрес надо как можно выше, лучше просто на максимум, т.е. вершину ставим не в конце всех переменных, а самый старший адрес памяти.

 

            ; FUNCTION _?set_CS (BEGIN)
                                          ; SOURCE LINE # 330
0000 1500        E     DEC     ?C_IBP
0002 A800        E     MOV     R0,?C_IBP
0004 A607              MOV     @R0,AR7
                                          ; SOURCE LINE # 332
0006 900000      R     MOV     DPTR,#SPI_mas+025EH
0009 E0                MOVX    A,@DPTR
000A 75F00A            MOV     B,#0AH
000D A4                MUL     AB
000E 2400        R     ADD     A,#LOW SPI_mas+0267H
0010 F582              MOV     DPL,A
0012 E5F0              MOV     A,B
0014 3400        R     ADDC    A,#HIGH SPI_mas+0267H
0016 F583              MOV     DPH,A
0018 E0                MOVX    A,@DPTR
0019 B40209            CJNE    A,#02H,?C0043
                                          ; SOURCE LINE # 333
                                          ; SOURCE LINE # 334
001C A800        E     MOV     R0,?C_IBP
001E E6                MOV     A,@R0
001F 24FF              ADD     A,#0FFH
0021 92A0              MOV     CS_SD_card,C
                                          ; SOURCE LINE # 335
0023 A2A0              MOV     C,CS_SD_card
                                          ; SOURCE LINE # 336
                                          ; SOURCE LINE # 337
0025         ?C0043:
0025 C0D0              PUSH    PSW
0027 0500        E     INC     ?C_IBP
0029 D0D0              POP     PSW
002B 22                RET     
            ; FUNCTION _?set_CS (END)

 

В вашем примере я не обнаружил вообще вызов в стек. Есть какое то сложение данных по адресу 0x60 и все. То что в инициализации у вас в адрес 0x60 укладывается значение 0x7C (вы говорили о записи туда 0xFF) мне пока не говорит что это именно ?C_IBP (посмотрите ее значение в map файле, найдите в файл .map адрес этой переменной. В моем примере она лежит по адресу 0x13 в области DATA (т.е. директ мемори, не в XDATA).

В общем странно это все. У меня не происходит пересечения областей памяти при вызове первызываемых функций. Мало того IBPSTACK для small модели и складывает оно все в индерект память, а не в xdata как вы указали. У вас весь код в какой модели памяти? Нет ли прагма для отдельных файлов со сменой модели памяти для этих файлов (так тоже можно и оно отлично работает, нужно только в определении функции прописать ее тип модели и тогда при вызове процедуры с другой моделью никаких проблем не будет).

 

удачи.

 

Просмотрел еще раз сообщения. Ощущение что код у вас в compact, а стек вы упорно пытаетесь проинитить для small.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...