NFLic

STM8 с нуля.

Стек в STM8 (Статья 5)

Стек (stack кипа) - область старших адресов оперативной памяти RAM, которая дополнительно к обычной адресации с помощью специальных команд имеет доступ по принципу стопки бумаг - последним положил первым забрал.

Стек используется для хранения адресов возврата из подпрограмм и из программ обработки прерываний, для сохранения содержимого регистов ядра STM8 на время обработки прерывани с восстановлением содержимого при выходе из программы обработки прерывания. Может использоваться для передачи переменных подпрограмме, для организации буфера данных и пр.

Стек имеет ограниченную глубину (напр. STM8S103F3 имеет глубину 513 байт если указатель стека SP инициализировать величиной $03FF) и заполняется от старших адресов к младшим. Переполнение стека никак не контролирутся микроконтроллером и может привести к потере данных если этих данных будет напихано в стек более чем его глубина.

Со стеком тесно связан регист указателя стека SP (Stack Pounter). Регистр всегда хранит адрес первой не занятой стопкой ячейки для бумаги (так называемой вершины/дна стека).

Далее все будет описано применительно к модели STM8S103F3, другие модели могут отличаться объемом памяти RAM и глубиной стека.

При сбросе/включении питания микроконтроллера STM8S103F3 указатель стека SP аппаратно инициализируется величиной $03FF (RAM END). Но инициализации стека не происходит если программно выполнить переход на вектор сброса $8000.

Память RAM у STM8S103F3 располагается в адресах $0000...$03FF. Стек может располагаться в адресах $01FF...$03FF. Чем ближе к границе памяти RAM расположить начальную вершину стека тем больше будет его глубина. Программная инициализация вершины стека:

 

       ldw     X, #$03FF  ; X <= RAM END
       ldw     SP, X      ; SP <= X

 

При этом стек пустой. Разберемся как он заполняется командами "push A", "push CC", "push #byte", "push lmem", "pushw X", "pushw Y" и как информация извлекается из стека командами "pop A", "pop CC", "pop lmem", "popw X", "popw Y" (команд "pop" на одну меньше, чем команд "push".

 
            ---------
    $03FE  |    0    |
            ---------
    $03FF  |    0    |
            ---------      SP = $03FF

В указателе стека содержится адрес $03FF (RAM END) самой старшей ячейки оперативной памяти RAM.

 

        push   A                  ; M(SP--) <= A
            ---------
    $03FE  |    0    |
            ---------
    $03FF  |    A    |     M($03FF) <= A ,   SP <= $03FF - 1 = $03FE
            ---------      SP = $03FE

По команде "push A" содержимое регистра A помещается в ячейку памяти RAM адрес которой находится в указателе стека SP (на данном этапе это $03FF) далее содержимое указателя стека SP уменьшается на единицу и указывает на не занятую стеком ячейку памяти RAM с адресом $03FE.

 

push CC ; M(SP--) <= CC --------- $03FD | 0 | --------- $03FE | CC | M($03FE) <= CC, SP <= $03FE - 1 = $03FD --------- $03FF | A | --------- SP = $03FD

По команде "push CC" содержимое регистра состояния CC помещается в ячейку памяти RAM адрес которой находится в указателе стека SP (на данном этапе это $03FE) далее содержимое указателя стека SP уменьшается на единицу и указывает на не занятую стеком ячейку памяти RAM с адресом $03FD.

 

push #byte ; M(SP--) <= #byte --------- $03FC | 0 | --------- $03FD | #byte | M($03FE) <= #byte, SP <= $03FD - 1 = $03FC --------- $03FE | CC | --------- $03FF | A | --------- SP = $03FC

По команде "push #byte" 8-разрядная константа(число) #byte помещается в ячейку памяти RAM адрес которой находится в указателе стека SP (на данном этапе это $03FD) далее содержимое указателя стека SP уменьшается на единицу и указывает на не занятую стеком ячейку памяти RAM с адресом $03FC.

 

        push   lmem                  ; M(SP--) <= lmem
            ---------
    $03FB  |    0    |
            ---------
    $03FC  |   lmem  |     M($03FE) <= lmem,  SP <= $03FC - 1 = $03FB
            ---------
    $03FD  |  #byte  |
            ---------
    $03FE  |   CC    |
            ---------
    $03FF  |    A    |
            ---------      SP = $03FB

По команде "push lmem" содержимое ячейки памяти с адресом lmem помещается в ячейку памяти RAM адрес которой находится в указателе стека SP (на данном этапе это $03FC) далее содержимое указателя стека SP уменьшается на единицу и указывает на не занятую стеком ячейку памяти RAM с адресом $03FB.

 

        pushw   X                  ; M(SP--) <= XL  M(SP--) <= XH
            ---------
    $03F9  |    0    |
            ---------
    $03FA  |   XH    |     M($03FE) <= XH,  SP <= $03FA - 1 = $03F9
            ---------
    $03FB  |   XL    |     M($03FE) <= XL,  SP <= $03FB - 1 = $03FA
            ---------
    $03FC  |  lmem   |
            ---------
    $03FD  |  #byte  |
            ---------
    $03FE  |   CC    |
            ---------
    $03FF  |    A    |
            ---------      SP = $03F9

По команде "pushw X" содержимое младшего байта индесного регистра X помещается в ячейку памяти RAM адрес которой находится в указателе стека SP (на данном этапе это $03FB) далее содержимое указателя стека SP уменьшается на единицу и указывает на не занятую стеком ячейку памяти RAM с адресом $03FA. Содержимое старшего байта индесного регистра X помещается в ячейку памяти RAM адрес которой находится в указателе стека SP (на данном этапе это $03FA) далее содержимое указателя стека SP уменьшается на единицу и указывает на не занятую стеком ячейку памяти RAM с адресом $03F9.

	
        pushw   Y                  ; M(SP--) <= YL  M(SP--) <= YH
            ---------
    $03F7  |    0    |
            ---------
    $03F8  |   YH    |     M($03F8) <= YH,  SP <= $03F8 - 1 = $03F7
            ---------
    $03F9  |   YL    |     M($03F9) <= YL,  SP <= $03F9 - 1 = $03F8
            ---------
    $03FA  |   XH    |
            ---------
    $03FB  |   XL    |
            ---------
    $03FC  |  lmem   |
            ---------
    $03FD  |  #byte  |
            ---------
    $03FE  |   CC    |
            ---------
    $03FF  |    A    |
            ---------      SP = $03F7

По команде "pushw Y" содержимое младшего байта индесного регистра Y помещается в ячейку памяти RAM адрес которой находится в указателе стека SP (на данном этапе это $03F9) далее содержимое указателя стека SP уменьшается на единицу и указывает на не занятую стеком ячейку памяти RAM с адресом $03F8. Содержимое старшего байта индесного регистра X помещается в ячейку памяти RAM адрес которой находится в указателе стека SP (на данном этапе это $03F8) далее содержимое указателя стека SP уменьшается на единицу и указывает на не занятую стеком ячейку памяти RAM с адресом $03F7.

 

Последовательность команд "push" "pushw" сохранения в стек может быть произвольной. Важно соблюдать обратную последовательность комманд по извлечению информации из стека. Но тут есть ньюансы. Если сохранять в стек аккумулятор или регистр состояния, то скорее всего будет необходимость извлекать из стека также в аккумулятор и регистр состояния. Если сохранять в стек содержимое индексных регистров X или Y, то в зависимости от необходимости, можно восстановить из стека соответствующее содержимое в регистов X и Y или наоборот Y и X. Если сохранить в стек однократно или последовательно некоторое количество раз содержимое регистра UART1_DR, то необходимо столько же выполнить извлечение из стека но уже не в регистр UART1_DR, а напр. аккумулятор. Главное соблюдать количество команд "push" "pushw" после сохранения конкрентоного содержимого в стеке и количество команд "pop" "popw" до извлечения этого же содержимого из стека.

 

       popw   Y                  ; YH <= M(++SP)  YL <= M(++SP)
            ---------
    $03F7  |    0    |
            ---------
    $03F8  |   YH    |     SP <= $03F7 + 1 = $03F8,  YH <= M($03F8)
            ---------
    $03F9  |   YL    |     SP <= $03F8 + 1 = $03F9,  YL <= M($03F9)
            ---------
    $03FA  |   XH    |
            ---------
    $03FB  |   XL    |
            ---------
    $03FC  |  lmem   |
            ---------
    $03FD  |  #byte  |
            ---------
    $03FE  |   CC    |
            ---------
    $03FF  |    A    |
            ---------      SP = $03F9

По команде "popw Y" сначала содержимое указателя SP увеличивается на единицу далее содержимое ячейки памяти RAM адрес которой находится в указателе SP (на данном этапе $03F8) копируется в старший байт индексного регистра Y. Потом содержимое указателя SP увеличивается на единицу и следом содержимое ячейки памяти RAM адрес которой находится в указателе SP (на данном этапе $03F9) копируется в младший байт индексного регистра Y. С этого момента ячейки с адресами $03F8 и $03F9 в памяти RAM считаются свободными (не занятыми).

 

       popw   X                  ; XH <= M(++SP)  XL <= M(++SP)
            ---------
    $03F7  |    0    |
            ---------
    $03F8  |   YH    |
            ---------
    $03F9  |   YL    |
            ---------
    $03FA  |   XH    |     SP <= $03F9 + 1 = $03FA,  YH <= M($03FA)
            ---------
    $03FB  |   XL    |     SP <= $03FA + 1 = $03FB,  YL <= M($03FB)
            ---------
    $03FC  |  lmem   |
            ---------
    $03FD  |  #byte  |
            ---------
    $03FE  |   CC    |
            ---------
    $03FF  |    A    |
            ---------      SP = $03FB

По команде "popw Y" сначала содержимое указателя SP увеличивается на единицу далее содержимое ячейки памяти RAM адрес которой находится в указателе SP (на данном этапе $03FA) копируется в старший байт индексного регистра X. Потом содержимое указателя SP увеличивается на единицу и следом содержимое ячейки памяти RAM адрес которой находится в указателе SP (на данном этапе $03FB) копируется в младший байт индексного регистра X. С этого момента ячейки с адресами $03FA и $03FB в памяти RAM считаются свободными (не занятыми).

       pop   lmem                  ; lmem <= M(++SP)
            ---------
    $03F7  |    0    |
            ---------
    $03F8  |   YH    |
            ---------
    $03F9  |   YL    |
            ---------
    $03FA  |   XH    |
            ---------
    $03FB  |   XL    |
            ---------
    $03FC  |  lmem   |     SP <= $03FB + 1 = $03FC,  lmem <= M($03FC)
            ---------
    $03FD  |  #byte  |
            ---------
    $03FE  |   CC    |
            ---------
    $03FF  |    A    |
            ---------      SP = $03FC

По команде "pop lmem" сначала содержимое указателя SP увеличивается на единицу далее содержимое ячейки памяти RAM адрес которой находится в указателе SP (на данном этапе $03FC) копируется в ячейку памяти с адресом lmem. С этого момента ячейка с адресом $03FC в памяти RAM считается свободной (не занятой).

 

       pop   lmem                  ; lmem <= M(++SP)
            ---------
    $03F7  |    0    |
            ---------
    $03F8  |   YH    |
            ---------
    $03F9  |   YL    |
            ---------
    $03FA  |   XH    |
            ---------
    $03FB  |   XL    |
            ---------
    $03FC  |  lmem   |
            ---------
    $03FD  |  #byte  |     SP <= $03FC + 1 = $03FD,  lmem <= M($03FD)
            ---------
    $03FE  |   CC    |
            ---------
    $03FF  |    A    |
            ---------      SP = $03FD

Не существует команды которая восстанавливает из стека обратно в константу(число). Но если число было сохранено в стек его надо извлечь. Выбор команды извлечения "pop A", "pop lmem" (маловероятно но не исключено "pop СС") зависит от назначения числа. По команде "pop lmem" сначала содержимое указателя SP увеличивается на единицу далее содержимое ячейки памяти RAM адрес которой находится в указателе SP (на данном этапе $03FD) копируется в ячейку памяти с адресом lmem. С этого момента ячейка с адресом $03FD в памяти RAM считается свободной (не занятой).

 

       pop   CC                  ; CC <= M(++SP)
            ---------
    $03F7  |    0    |
            ---------
    $03F8  |   YH    |
            ---------
    $03F9  |   YL    |
            ---------
    $03FA  |   XH    |
            ---------
    $03FB  |   XL    |
            ---------
    $03FC  |  lmem   |
            ---------
    $03FD  |  #byte  |
            ---------
    $03FE  |   CC    |     SP <= $03FD + 1 = $03FE,  CC <= M($03FE)
            ---------
    $03FF  |    A    |
            ---------      SP = $03FE

По команде "pop CC" сначала содержимое указателя SP увеличивается на единицу далее содержимое ячейки памяти RAM адрес которой находится в указателе SP (на данном этапе $03FE) копируется в регистр состояния CC. С этого момента ячейка с адресом $03FE в памяти RAM считается свободной (не занятой).

 

       pop   A                  ; A <= M(++SP)
            ---------
    $03F7  |    0    |
            ---------
    $03F8  |   YH    |
            ---------
    $03F9  |   YL    |
            ---------
    $03FA  |   XH    |
            ---------
    $03FB  |   XL    |
            ---------
    $03FC  |  lmem   |
            ---------
    $03FD  |  #byte  |
            ---------
    $03FE  |   CC    |
            ---------
    $03FF  |    A    |     SP <= $03FE + 1 = $03FF,  A <= M($03FF)
            ---------      SP = $03FF

По команде "pop A" сначала содержимое указателя SP увеличивается на единицу далее содержимое ячейки памяти RAM адрес которой находится в указателе SP (на данном этапе $03FE) копируется в аккумулятор A. С этого момента ячейка с адресом $03FF в памяти RAM считается свободной (не занятой). Теперь указатель SP опять содержит адрес самой старшей ячейки памяти RAM.

 

Стек используется для хранения адресов возврата из подпрограмм. Рассмотрим что происходит при вызове подпрограммы и возврате из подпрограммы

 
        call  lmem   ; M(SP--)<=PCL M(SP--)<-PCH PC<=lmem
        ; next comand
    	
    lmem: 
        ; some code
    	ret          ; PCH <= M(++SP)   PCL <= M(++SP)

Командой "call lmem" в стек сохраняется адрес следующей команды, следом в счетчик команд копируется адрес вызова подпрограммы lmem. Командой "ret" из стека в счетчик команд восстанавливается адрес следующей за "call lmem" команды. Байт PCE счетчика команд PC не сохраняется в стек командой "call lmem" и не восстанавливается из стека командой "ret" поэтому команды "call lmem" и "ret" действуют только в пределах своей секции памяти $xx0000...$xxFFFFF.

 
        callr  ssof   ; M(SP--)<=PCL M(SP--)<-PCH PC<=PC+ssof
        ; next comand
    	
    lmem: 
        ; some code
    	ret          ; PCH <= M(++SP)   PCL <= M(++SP)

Командой "callr ssof" в стек сохраняется адрес следующей команды, следом в счетчик команд копируется адрес вызова подпрограммы PC+ssof. Командой "ret" из стека в счетчик команд восстанавливается адрес следующей за "callr ssof" команды. Команда "callr ssof" действует в пределах страницы памяти (-128...+127).

 
        callf  emem   ; M(SP--)<=PCL M(SP--)<-PCH M(SP--)<-PCE PC<=emem
        ; next comand
    	
    lmem: 
        ; some code
    	retf          ; PCE <= M(++SP) PCH <= M(++SP)   PCL <= M(++SP)

Командой "callf emem" в стек сохраняется адрес следующей команды, следом в счетчик команд копируется адрес вызова подпрограммы emem. Командой "retf" из стека в счетчик команд восстанавливается адрес следующей за "callf emem" команды. Команда "callf emem" и "retf" действуют в пределах всего адресного пространства STM8.

 

Стек также используется для хранения адресов возврата из программ обработки прерываний. Рассмотрим что происходит со стеком при вызове прерывания и возврате из прерывания. Условимся, что в указателе SP находится адрес $03FF RAM END. При срабатывании какого-либа прерывания заканчивается выполнение текущей команды, в стек сохраняется содержимое регистров PC(адрес следующей команды), Y, X, A, CC в следующем порядке:

        pop   A                  ; A <= M(++SP)
            ---------
    $03F6  |    0    |
            ---------
    $03F7  |   CC    |     M($03F7) <= CC,   SP <= $03F7 - 1 = $03F6
            ---------
    $03F8  |    A    |     M($03F8) <= A,    SP <= $03F8 - 1 = $03F7
            ---------
    $03F9  |   YH    |     M($03F9) <= XH,   SP <= $03F9 - 1 = $03F8
            ---------
    $03FA  |   XL    |     M($03FA) <= XL,   SP <= $03FA - 1 = $03F9
            ---------
    $03FB  |   YH    |     M($03FB) <= YH,   SP <= $03FB - 1 = $03FA
            ---------
    $03FC  |   YL    |     M($03FC) <= YL,   SP <= $03FC - 1 = $03FB
            ---------
    $03FD  |   PCE   |     M($03FD) <= PCE,  SP <= $03FD - 1 = $03FC
            ---------
    $03FE  |   PCH   |     M($03FE) <= PCH,  SP <= $03FE - 1 = $03FD
            ---------
    $03FF  |   PCL   |     M($03FF) <= PCL,  SP <= $03FF - 1 = $03FE
            ---------      SP = $03F6

 

В разряды I0 и I1 регистра статуса CC копируется информация о приоритете прерывания из соответствующего регистра ITC_SPR ($7F70...$7F7F). В счетчик программ PC загружается вектор сработавшего прерывания. После чего командой "INT dst" происходит переход к программе обработки прерывания.

По завершению программы обработки прерывания командой "iret" из стека восстанавливается содержимое регистров CC, A, X, Y, PC в следующем порядке:

        iret    ; Interrupt Return      ; CC<=M(++SP) A<=M(++SP) XH<=M(++SP)
                                        ; XL<=M(++SP) YH<=M(++SP) YL<=M(++SP) 
                                        ; PCE<=M(++SP) PCH<=M(++SP) PCL<=M(++SP) 
            ---------
    $03F6  |    0    |
            ---------
    $03F7  |   CC    |     SP <= $03F6 + 1 = $03F7, CC  <= M($03F7)  
            ---------
    $03F8  |    A    |     SP <= $03F7 + 1 = $03F8, A   <= M($03F8) 
            ---------
    $03F9  |   YH    |     SP <= $03F8 + 1 = $03F9, YH  <= M($03F9) 
            ---------
    $03FA  |   YL    |     SP <= $03F9 + 1 = $03FA, YL  <= M($03FA) 
            ---------
    $03FB  |   YH    |     SP <= $03FA + 1 = $03FB, YH  <= M($03FB) 
            ---------
    $03FC  |   YL    |     SP <= $03FB + 1 = $03FC, YL  <= M($03FC) 
            ---------
    $03FD  |   PCE   |     SP <= $03FC + 1 = $03FD, PCE <= M($03FD) 
            ---------
    $03FE  |   PCH   |     SP <= $03FD + 1 = $03FE, PCH <= M($03FE) 
            ---------
    $03FF  |   PCL   |     SP <= $03FE + 1 = $03FF, PCL <= M($03FF) 
            ---------      SP = $03FF												 

Поcле восстановления младшего байта счетчика команд PC продолжится выполнение основной программы.

 

Команды в которых участвует указатель стека SP:

 

   00 XX          NEG    (soff,SP)         ; Negate (Logical 2's complement)     M(soff+SP) <= -M(soff+SP)
   03 XX          CPL    (soff,SP)         ; Logical 1's complement              M(soff+SP) <= /M(soff+SP)
   04 XX          SRL    (soff,SP)         ; Shift Right Logical                 M(soff+SP).{0->#7->#6->#5->#4->#3->#2->#1->#0->CC.C}
   06 XX          RRC    (soff,SP)         ; Rotate Right Logical through Carry  M(soff+SP).{CC.C->#7->#6->#5->#4->#3->#2->#1->#0->CC.C}
   07 XX          SRA    (soff,SP)         ; Shift Right Arithmetic              M(soff+SP).{#7->#6->#5->#4->#3->#2->#1->#0->CC.C}
   08 XX          SLA    (soff,SP)         ; Shift Left Arithmetic               M(soff+SP).{CC.C<-#7<-#6<-#5<-#4<-#3<-#2<-#1<-#0<-0}
   08 XX          SLL    (soff,SP)         ; Shift Left Logical                  M(soff+SP).{CC.C<-#7<-#6<-#5<-#4<-#3<-#2<-#1<-#0<-0}
   09 XX          RLC    (soff,SP)         ; Rotate Left Logical through Carry   M(soff+SP).{CC.C<-#7<-#6<-#5<-#4<-#3<-#2<-#1<-#0<-CC.C}
   0A XX          DEC    (soff,SP)         ; Decrement                           M(soff+SP) <= M(soff+SP) - 1
   0C XX          INC    (soff,SP)         ; Increment                           M(soff+SP) <= M(soff+SP) + 1
   0D XX          TNZ    (soff,SP)         ; Test for Negative or Zero           {CC.N, CC.Z} <= Test{ M(soff+SP }
   0E XX          SWAP   (soff,SP)         ; Swap Nibbles                        M(soff+SP).low <-> M(soff+SP).high
   0F XX          CLR    (soff,SP)         ; Clear                               M(soff+SP) <= 0
   10 XX          SUB    A, (soff,SP)      ; Subtraction                         A <= A - M(soff+SP)
   11 XX          CP     A, (soff,SP)      ; Compare                             {CC.N, CC.Z, CC.C} <= Test{ A - M(soff+SP) }
   12 XX          SBC    A, (soff,SP)      ; Subtraction                         A <= A - M(soff+SP)
   13 XX          CPW    X, (soff,SP)      ; Compare Word                        {CC.N, CC.Z, CC.C} <= Test{ X - M(soff+SP).w }
   14 XX          AND    A, (soff,SP)      ; Logical AND                         A <= A AND M(soff+SP)
   15 XX          BCP    A, (soff,SP)      ; Logical Bit Compare                 {CC.N, CC.Z} <= Test{ A AND M(soff,SP) }
   
   17 XX          LDW    (soff,SP), Y      ; Load Word                           M(soff+SP) <= Y
   18 XX          XOR    A, (soff,SP)      ; Logical Exclusive OR                A <= A XOR M(soff+SP)
   19 XX          ADC    A, (soff,SP)      ; Addition with Carry                 A <= A + M(soff+SP) + CC.C
   1A XX          OR     A, (soff,SP)      ; Logical OR                          A <= A OR M(soff+SP)
   1B XX          ADD    A, (soff,SP)      ; Addition                            A <= A + M(soff+SP)
   
   1E XX          LDW    X, (soff,SP)      ; Load Word                           X <= M(soff+SP)
   
   32 MS LS       POP    lmem              ; Pop from stack                      SP++  M(lmem) <= M(SP)
   4B XX          PUSH   #byte             ; Push onto the Stack                 M(SP--) <= #byte
   52 XX          SUB    SP, #byte         ; Subtraction                         SP <= SP - #byte
   5B XX          ADDW   SP, #byte         ; Addition                            SP <= SP + #byte
   6B XX          LD     (soff,SP), A      ; Load                                A <= M(soff+SP)
   7B XX          LD     A, (soff,SP)      ; Load                                A <= M(soff+SP)
   80             IRET                     ; Interrupt Return                    CC<=M(++SP) A<=M(++SP) XH<=M(++SP)
                                           ;                                     XL<=M(++SP) YH<=M(++SP) YL<=M(++SP) 
                                           ;                                     PCE<=M(++SP) PCH<=M(++SP) PCL<=M(++SP)
   84             POP    A                 ; Pop from stack                      A  <= M(++SP)  preincremrnt
   85             POPW   X                 ; Pop Word from stack                 XH <= M(++SP)  XL <= M(++SP)
90 85             POPW   Y                 ; Pop Word from stack                 YH <= M(++SP)  YL <= M(++SP)
   86             POP    CC                ; Pop from stack                      CC <= M(++SP)  preincremrnt
   87             RETF                     ; Far Return from subroutine          PCE<=M(++SP) PCH<=M(++SP) PCL<=M(++SP)
   88             PUSH   A                 ; Push into the Stack                 M(SP--) <= A   postdecremrnt
   89             PUSHW  X                 ; Push Word onto the Stack            M(SP--) <= XL  M(SP--) <= XH
90 89             PUSHW  Y                 ; Push Word onto the Stack            M(SP--) <= YL  M(SP--) <= YH
   8A             PUSH   CC                ; Push into the Stack                 M(SP--) <= CC  postdecremrnt 
   8D ExtB MS LS  CALLF  emem              ; Call Far Subroutine                 M(SP--)<=PCL M(SP--)<-PCH M(SP--)<-PCE PC<=emem
92 8D MS LS       CALLF  [lptr.e]          ; Call Far Subroutine                 M(SP--)<=PCL M(SP--)<-PCH M(SP--)<-PCE PC<=M(lptr).e											 
   94             LDW    SP, X             ; Load Word                           SP <= X
90 94             LDW    SP, Y             ; Load Word                           SP <= Y
   96             LDW    X, SP             ; Load Word                           X  <= SP
90 96             LDW    Y, SP             ; Load Word                           Y  <= SP											 
   AD XX          CALLR  ssoff             ; CALL Subroutine Relative            M(SP--)<=PCL M(SP--)<-PCH PC<=PC+ssoff
   CD MS LS       CALL   lmem              ; Call Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=lmem
72 CD MS LS       CALL   [lptr.w]          ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(lptr).w
92 CD XX          CALL   [sptr.w]          ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(sptr).w
   DD MS LS       CALL   (loff,X)          ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(loff+X).w
72 DD MS LS       CALL   ([lptr.w],X)      ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(M(lptr).w+X).w
90 DD MS LS       CALL   (loff,Y)          ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(loff+Y).w
91 DD XX          CALL   ([sptr.w],Y)      ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(M(sptr).w+Y).w
92 DD XX          CALL   ([sptr.w],X)      ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(M(sptr).w+X).w	
72 F2 XX          SUBW   Y, (soff.w,SP).w  ; Subtraction                         Y <= Y - M(soff.w+SP).w
   ED XX          CALL   (soff,X)          ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(soff+X).w
90 ED XX          CALL   (soff,Y)          ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(soff+Y).w
72 F0 XX          SUBW   X, (soff,SP)      ; Subtraction Word                    X <= X - M(soff+SP).w
72 F9 XX          ADDW   Y, (soff,SP)      ; Addition Word                       Y <= Y  +  M(soff+SP)
72 FB XX          ADDW   X, (soff,SP)      ; Addition Word                       X <= X  +  M(soff+SP)
   FD             CALL   (X)               ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(X).w
90 FD             CALL   (Y)               ; CALL Subroutine (Absolute)          M(SP--)<=PCL M(SP--)<-PCH PC<=M(Y).w

 

Теперь рассмотрим где может располагаться стек.

            ---------
    $03FF  |         | RAM END    верхняя граница стека
            ---------
    $03F7  |         |  
            ---------
     ...   |         |
            ---------
    $0200  |         | 
            ---------
    $01FF  |         |            нижняя граница стека
            ---------
    $01FE  |         | 
            ---------
     ...   |         | 
            ---------
    $0001  |         | 
            ---------
    $0000  |         | RAM START
            ---------  												 

Аппартно у стека существуют две границы. Верхняя граница совмещена со старшей ячейкой памяти RAM. Нижняя граница расположено примерно посередине области RAM.

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

 

Рассмотрим расположение стека в области $01FF...#$03FF.

При включении указатель вершины стека SP инициализируется величиной $03FF. При наполнении стека содержимое указателя приблизается к величине $01FF, по достижению которой при следующей команде "push" указатель принимает первоначальное значение $03FF. С этого момента стек начинает повторять свою траекторию, затирая ранее сохраненную информацию. Благодаря тому, что стек замкнулся в кольцо, гарантируется целостность последних 513 байт помещенных в стек вне зависимости от текущего положения вершины стека. При извлечении информации из стека содержимое указателя повторяет траекторию в обратном направлении. После достижения верхней границы $03FF указатель SP принимает содержимое $01FF и так по кольцу.

 

Несколько иначе стек ведет себя при расположении под нижней границей $01FF.

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

 

Машинные коды STM8 и команды ассемблера здесь. Адресное пространство STM8S103F3 тут.

 

[Принятые сокращения (Статья 4)][Оглавление.] [Адресация в STM8 (Статья 6)]