1kvi1 0 17 марта, 2011 Опубликовано 17 марта, 2011 (изменено) · Жалоба Всем, привет! Делаю первый проект на С для С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 Изменено 17 марта, 2011 пользователем 1kvi1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
O.L. 0 17 марта, 2011 Опубликовано 17 марта, 2011 · Жалоба Определение: 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, дополнительно под все Ваши локальные переменные, загружаемые константы, а так же стек, скорее всего просто не хватает памяти. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1kvi1 0 17 марта, 2011 Опубликовано 17 марта, 2011 · Жалоба 0000B7H PDATA + 000CECH XDATA Памяти хватает, проблема в том что указатель программного стека не инициализируется на вершину. Инициализироваться он должен в стартап коде, но его местоположение заранее не известно. Как узнать адрес и размер программного стека или как заставить линкер самому вычислять? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
O.L. 0 17 марта, 2011 Опубликовано 17 марта, 2011 · Жалоба На самом деле не совсем так. Судя по таблице линкера 0000B7H PDATA + 000CECH XDATA + 000FFFH HDATA. Стек то ведь то же туда же укладывается. Посмотрите в симуляторе, что пишется в регистр SP. Можно так же "покрутить" программу и посмотреть значение SP_max. Впрочем можно посмотреть эти значения и в листинге, если он генерируется. Потом изменить модель памяти на LARGE и посмотреть все те же значения. Уверяю Вас, все строго определено и ни компайлер ни линкер каких либо вольностей себе не позволяют. Несколько лет назад переживал примерно похожий "кризис веры в Keil", пока не обнаружил, что в одной из моих процедур маска ограничивающая размер буфера была по ошибке выбрана больше размера самого буфера на целый разряд. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AndreyS 0 18 марта, 2011 Опубликовано 18 марта, 2011 (изменено) · Жалоба Всем, привет! Делаю первый проект на С для С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. ; ;------------------------------------------------------------------------------ Удачи Изменено 18 марта, 2011 пользователем AndreyS Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1kvi1 0 19 марта, 2011 Опубликовано 19 марта, 2011 · Жалоба Старт-ап код я исправил и указал вершину на 0x100. Я так понимаю линкер должен это учесть и не располагать переменые и структуры ниже адреса 0x100? Но он так не делает и игнорирует. Сейчас после каждой компиляции проверяю по листингу с какого адреса лежат переменные и в стартапе устанавливаю соответствующее значение. Кроме того ассемблерная инструкция - совсем не указание линкеру освободить данную область памяти? Как решить проблему? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1kvi1 0 19 марта, 2011 Опубликовано 19 марта, 2011 · Жалоба Вот получается такая таблица памяти. В старт-апе установлена вершина 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
O.L. 0 19 марта, 2011 Опубликовано 19 марта, 2011 · Жалоба Старт-ап код я исправил и указал вершину на 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 0 22 марта, 2011 Опубликовано 22 марта, 2011 · Жалоба Цитата(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'ом (последний явно совершенней). Просьба напишите как сделать правильно - очень не хочется переносить проект под другую среду. Заранее спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
O.L. 0 22 марта, 2011 Опубликовано 22 марта, 2011 (изменено) · Жалоба Ну вот собственно вопрос - почему среда сама не ставит адрес вершины стека и как оптимизировать этот процесс. Я не так хорошо знаком с 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. Хотел помочь, но увы :( Изменено 22 марта, 2011 пользователем O.L. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1kvi1 0 22 марта, 2011 Опубликовано 22 марта, 2011 · Жалоба Очень жалко, что ответа найти не удается. Проблема в том что я не знаю какую именно цифру ставить как вершину стека. Вот если посмотреть листинг линкера - какой алгоритм выбора вершины? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AndreyS 0 22 марта, 2011 Опубликовано 22 марта, 2011 · Жалоба Добрый день. Странный код у вас при вызове перевызываемой функции. Вот пример моей функции и ее листинг Вот сама процедура на Си (первые цифры - это номера строк в коде, что бы легче было произвести сравнение с листингом) На отсутствие 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. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться