汇编代码抛出栈溢出错误,我找不到原因。

huangapple go评论55阅读模式
英文:

Assembly code throwing a stack overflow error and I can't find why

问题

我在为课程项目工作,必须在汇编中编写某些内容,我正在使用 PIC 16F887。我知道它具有 8 级堆栈,但我找不到为什么/在哪里超出堆栈的原因。

代码看起来像这样:

targ_temp	EQU	0x20		
CONT1		EQU	0x20
CONT2		EQU	0x21
TTEMPU		EQU	0x22
TTEMPD		EQU	0X23
aux		EQU	0X24
FLAGS		EQU	0X25
TEMPU		EQU	0X26
TEMPD		EQU	0X27
PESO		EQU	0X28
CONT		EQU	0X30

;**********************************************************************

	ORG     0x000             
  	goto    main              
	ORG     0x004             
	BTFSC INTCON,2
	CALL TIMEROVERFLOW
	BTFSC INTCON,1
	CALL SENSORVASO
	BTFSC INTCON,0
	CALL LEERTECLADO
	BTFSC PIR1,6
	CALL CONVERSOR
	;BTFSC PIR1,5
	;CALL EUSARTRECIEVE
	;BTFSC PIR1,4
	;CALL EUSARTTRANSMIT
	// 清除标志位
	retfie                    ; 从中断返回

main
	// 设置
	GOTO $

LEERTECLADO                       ; 轮询键盘
	call DELAY
	movlw 0x0F
	iorwf PORTC,1
	MOVLW 0XFF    ; 我用这个来检查最后是否实际按下按钮,或者是否释放/按下了其他我没有映射的按键
	BCF PORTC,3
	BTFSS PORTB,7 ; <- 这是堆栈溢出的地方
	movlw 0x1
	BTFSS PORTB,6
	movlw 0x2
	BTFSS PORTB,5
	movlw 0x3
	BTFSS PORTB,4
	goto tempres
	clrf PORTC
	bsf PORTC,3
	bcf PORTC,2
	BTFSS PORTB,7
	movlw 0x4
	BTFSS PORTB,6
	movlw 0x5
	BTFSS PORTB,5
	movlw 0x6
	BTFSS PORTB,4
	goto tempset
	clrf PORTC
	BSF PORTC,2
	BCF PORTC,1
	BTFSS PORTB,7
	movlw 0x7
	BTFSS PORTB,6
	movlw 0x8
	BTFSS PORTB,5
	movlw 0x9
	clrf PORTC
	BSF PORTC,1
	BCF PORTC,0
	BTFSS PORTB,6
	movlw 0x0
	BCF PORTC,3
	BCF PORTC,2
	BCF PORTC,1
	BCF PORTC,0
	addlw 0x1           ; 在这里我检查 w 是否溢出,如果溢出,意味着没有按下按钮
	btfsc STATUS,2      ;
	goto term           ;
	sublw 0x1           ; 如果没有溢出,我将它恢复到原始值
	movwf aux
	movf TTEMPU,0
	movwf TTEMPD
	movf aux,0
	movwf TTEMPU
	goto term

tempset
	movlw 0X26
	movwf FSR
	BCF PORTA,7
	BSF PORTA,6
	BCF STATUS,7
	BCF STATUS,6
	goto term

tempres
	clrf TTEMPU
	clrf TTEMPD
	MOVLW 0x22
	movwf FSR
	BCF PORTA,7
	BSF PORTA,6
	BCF STATUS,7
	BCF STATUS,6		
term
	return

CONVERSOR	
	BTFSC FLAGS,6
	GOTO SERV
	CLRF TEMPD
	CLRF TEMPU
	MOVLW .25
adec
	SUBWF ADRESH,1
	INCF TEMPD,1
	BTFSC STATUS,0
	GOTO over
	BTFSS STATUS,2
	GOTO adec
	GOTO tempter
over
	DECF TEMPD,1
	ADDWF ADRESH,1
	MOVLW .10
	SUBWF TEMPD,0
	BTFSC STATUS,2
	GOTO cien
	MOVLW .3
aun
	SUBWF ADRESH,1
	INCF TEMPU,1
	BTFSC STATUS,0
	GOTO overun
	BTFSS STATUS,2
	GOTO aun
	GOTO tempter
overun
	DECF TEMPU,1	
	GOTO tempter
cien
	MOVLW .10
	MOVWF TEMPD
	CLRF TEMPU
	BCF PORTA,4
	GOTO FINADC
tempter
	MOVF TEMPD,0
	SUBWF TTEMPD,0
	BTFSC STATUS,0
	GOTO apagar
	BTFSS STATUS,2
	GOTO mant
	MOVF TEMPU,0
	SUBWF TTEMPU,0
	BTFSC STATUS,0
	GOTO apagar
	BTFSS STATUS,2
	GOTO apagar
mant
	BSF PORTA,4
	BCF FLAGS,7
	GOTO FINADC
apagar
	BCF PORTA,4
	BSF FLAGS,7
	GOTO FINADC

SERV
	MOVLW PESO
	SUBWF ADRESH,0
	BTFSC STATUS,0
	GOTO VLLENO
	BTFSS STATUS,2
	GOTO VLLENO
	GOTO FINADC
VLLENO
	BCF FLAGS,6
	BCF PORTA,5
	BCF ADCON0,3
	INCF CONT,1
	MOVFW CONT
	BANKSEL TXREG
	MOVWF TXREG
	BSF TXSTA,5
	BANKSEL CONT

FINADC
	BSF ADCON0,1
	RETURN

SENSORVASO
	call DELAY
	BTFSS FLAGS,7
	GOTO ENDVASO
	BSF PORTA,5
	BSF FLAGS,6
	BSF ADCON0,3
ENDVASO
	return

TIMEROVERFLOW
	btfsc PORTA,7
	goto inver
	incf FSR,1
	movf INDF,0
	call TABLA
	movwf PORTD
	BCF PORTA,6
	BSF PORTA,7
	goto termi


<details>
<summary>英文:</summary>

I&#39;m working on a project for a course and I have to program something in Assembly, I&#39;m working with the PIC 16F887, I know it has a 8 level stack and I can&#39;t find why/where I&#39;m going over it.


The code looks something like this:

targ_temp EQU 0x20
CONT1 EQU 0x20
CONT2 EQU 0x21
TTEMPU EQU 0x22
TTEMPD EQU 0X23
aux EQU 0X24
FLAGS EQU 0X25
TEMPU EQU 0X26
TEMPD EQU 0X27
PESO EQU 0X28
CONT EQU 0X30

;**********************************************************************

ORG     0x000             
goto    main              
ORG     0x004             
BTFSC INTCON,2
CALL TIMEROVERFLOW
BTFSC INTCON,1
CALL SENSORVASO
BTFSC INTCON,0
CALL LEERTECLADO
BTFSC PIR1,6
CALL CONVERSOR
;BTFSC PIR1,5
;CALL EUSARTRECIEVE
;BTFSC PIR1,4
;CALL EUSARTTRANSMIT
// clearing flags
retfie                    ; return from interrupt

main
//setup
GOTO $
LEERTECLADO ;polling the keypad
call DELAY
movlw 0x0F
iorwf PORTC,1
MOVLW 0XFF ;I use this to check at the end if a button is actually pressed, or if it was let go/pressed some other key that I'm not mapping
BCF PORTC,3
BTFSS PORTB,7 ;<- this is where the stack overflow originates from
movlw 0x1
BTFSS PORTB,6
movlw 0x2
BTFSS PORTB,5
movlw 0x3
BTFSS PORTB,4
goto tempres
clrf PORTC
bsf PORTC,3
bcf PORTC,2
BTFSS PORTB,7
movlw 0x4
BTFSS PORTB,6
movlw 0x5
BTFSS PORTB,5
movlw 0x6
BTFSS PORTB,4
goto tempset
clrf PORTC
BSF PORTC,2
BCF PORTC,1
BTFSS PORTB,7
movlw 0x7
BTFSS PORTB,6
movlw 0x8
BTFSS PORTB,5
movlw 0x9
clrf PORTC
BSF PORTC,1
BCF PORTC,0
BTFSS PORTB,6
movlw 0x0
BCF PORTC,3
BCF PORTC,2
BCF PORTC,1
BCF PORTC,0
addlw 0x1 ;here I check if w overflows, if it does it means no buttons were pressed
btfsc STATUS,2 ;
goto term ;
sublw 0x1 ;if it didn't overflow I bring it back to the original value
movwf aux
movf TTEMPU,0
movwf TTEMPD
movf aux,0
movwf TTEMPU
goto term
tempset movlw 0X26
movwf FSR
BCF PORTA,7
BSF PORTA,6
BCF STATUS,7
BCF STATUS,6
goto term
tempres clrf TTEMPU
clrf TTEMPD
MOVLW 0x22
movwf FSR
BCF PORTA,7
BSF PORTA,6
BCF STATUS,7
BCF STATUS,6
term return
CONVERSOR
BTFSC FLAGS,6
GOTO SERV
CLRF TEMPD
CLRF TEMPU
MOVLW .25
adec SUBWF ADRESH,1
INCF TEMPD,1
BTFSC STATUS,0
GOTO over
BTFSS STATUS,2
GOTO adec
GOTO tempter
over DECF TEMPD,1
ADDWF ADRESH,1
MOVLW .10
SUBWF TEMPD,0
BTFSC STATUS,2
GOTO cien
MOVLW .3
aun SUBWF ADRESH,1
INCF TEMPU,1
BTFSC STATUS,0
GOTO overun
BTFSS STATUS,2
GOTO aun
GOTO tempter
overun DECF TEMPU,1
GOTO tempter
cien MOVLW .10
MOVWF TEMPD
CLRF TEMPU
BCF PORTA,4
GOTO FINADC
tempter MOVF TEMPD,0
SUBWF TTEMPD,0
BTFSC STATUS,0
GOTO apagar
BTFSS STATUS,2
GOTO mant
MOVF TEMPU,0
SUBWF TTEMPU,0
BTFSC STATUS,0
GOTO apagar
BTFSS STATUS,2
GOTO apagar
mant BSF PORTA,4
BCF FLAGS,7
GOTO FINADC
apagar BCF PORTA,4
BSF FLAGS,7
GOTO FINADC
SERV
MOVLW PESO
SUBWF ADRESH,0
BTFSC STATUS,0
GOTO VLLENO
BTFSS STATUS,2
GOTO VLLENO
GOTO FINADC
VLLENO BCF FLAGS,6
BCF PORTA,5
BCF ADCON0,3
INCF CONT,1
MOVFW CONT
BANKSEL TXREG
MOVWF TXREG
BSF TXSTA,5
BANKSEL CONT
FINADC BSF ADCON0,1
RETURN
SENSORVASO
call DELAY
BTFSS FLAGS,7
GOTO ENDVASO
BSF PORTA,5
BSF FLAGS,6
BSF ADCON0,3
ENDVASO return
TIMEROVERFLOW
btfsc PORTA,7
goto inver
incf FSR,1
movf INDF,0
call TABLA
movwf PORTD
BCF PORTA,6
BSF PORTA,7
goto termi
inver
DECF FSR,1
movf INDF,0
call TABLA
movwf PORTD
BCF PORTA,7
BSF PORTA,6
termi
return
TABLA
ADDWF PCL,F
RETLW b'11111100' ;devuelve 0
RETLW b'01100000' ;1
RETLW b'11011010' ;2
RETLW b'11110010' ;3
RETLW b'01100110' ;4
RETLW b'10110110' ;5
RETLW b'10111110' ;6
RETLW b'11100000' ;7
RETLW b'11111110' ;8
RETLW b'11110110' ;9
RETLW b'11111010' ;.0
DELAY ;delay routine mainly for debouncing
movlw .3
movwf CONT2
ext
movlw .250
movwf CONT1
int
decfsz CONT1,1
goto int
decfsz CONT2,1
goto ext
return
END

Please excuse the tags in spanish, I get a stack overflow warning when simulating on proteus and touching the button that connects RB7 and RC3, also implemented it on a breadboard and had (I believe) the same thing happens, meaning that from what I could see the displays stopped switching and only one would get stuck with the same value displayed regardless of what I did. 

I was using proteus to check everything was working as intending before moving it to the board until I came across this. The exact error it launches is: [PIC16 CORE] PC=0x00E9. Stack overflow executing CALL instruction. [U1]
I tried debugging on MPLAB X using the asyncronous stimulus, I followed the code line by line and it worked as intended. One thing I read on another forum as a response to someone having a similar issue was that the value added in tabla (adding it to pc) could be negative and it could go to a different call and overflow that way, but I can&#39;t see that happening here since it&#39;s a piece of code on a interrupt, so it can&#39;t be cut short, and it either places a value between 0-9 or it returns. I&#39;ll leave a chunk of code that I don&#39;t really think is necessary but maybe there&#39;s something there I&#39;m not seeing. I&#39;m at a loss.

</details>


# 答案1
**得分**: 2

堆栈溢出发生在`TIMEROVERFLOW`函数/例程中,我不能证明为什么会发生,但是使用指针和间接寻址会发送错误的W寄存器值来调用TABLA,这导致程序计数器(PC)跳转到不应该的位置,尽管我在设置中将值初始化为0。我用一个检查我尝试显示的内容的标志替换了这个例程,而不是依赖指针,现在不再出现堆栈溢出。

<details>
<summary>英文:</summary>

The Stack Overflow happened in the `TIMEROVERFLOW` function/routine, I can&#39;t attest to why, but using the pointer and indirect addressing was sending a wrong W reg value calling TABLA, which led to the pc going places it shouldn&#39;t, even though I initialized the values as 0 in the setup. I replaced the routine with a flag that checks what I&#39;m trying to show instead of relying on the pointer and I&#39;m not getting the stack overflow anymore. 

</details>



# 答案2
**得分**: 1

是的,它确实*看起来*你只使用了三个级别(中断本身,调用特定处理函数,以及其中一些调用延迟的函数)<sup>(1)</sup>。

我唯一能建议的是,你首先找出`0x00e9`处的代码片段,这是堆栈溢出错误消息中列出的地址。这可能会提供一些线索。

然后,也许在`TABLA`的开头放置一些保护代码,以便它只为特定可接受的值执行加法操作。如果不是这样,就执行其他操作,比如选择默认值或进入像你的`main: goto $`那样的另一个无限循环。希望你可以通过地址总线上永不变化的PC来捕获它。

在我看来,这似乎是在你的正常(三级)路径之外调用的唯一可能性。例如,`addw pcl, f` *可能*最终会有效地跳回到中断例程中的某个位置,再次调用其中一个处理函数。多做几次,嘣,你的堆栈就耗尽了。

根据你的仿真器有多好,你可以跟踪程序计数器的每个值,并查看它的去向。

---

<sup>(1)</sup> 电路调试器可能会添加另一个级别,但仍然只有四个,远远在`16F877`的八级限制内。

<details>
<summary>英文:</summary>

Yes, it certainly *looks* like you only ever use three levels (the interrupt itself, the call to the specific handler function, and a call from some of them to delay)&lt;sup&gt;(1)&lt;/sup&gt;.

All I can suggest is that you first figure out which piece of code is at `0x00e9`, the address listed in the stack overflow error message. That may provide a clue.

Then perhaps put some protection code at the start of `TABLA` so that it only does the add for specific acceptable value. If not, do something else, such as choose a default value or enter another infinite loop like your `main: goto $` one. Hopefully you can then pick it up by virtue of a never changing PC on the address bus.

That seems to me to be the only vector for calling outside of your normal (three-level) pathways. For example, the `addw pcl, f` *may* end up effectively jumping back to somewhere in the interrupt routine and once again calling one of the handler functions. Do that a couple of times and, bang, there&#39;s your stack exhausted.

Depending on how good your emulators are, you may be able to track every single value of the program counter and see where it&#39;s going.

---

&lt;sup&gt;(1)&lt;/sup&gt; The in-circuit debugger may add another level but that&#39;s *still* only four, well within the limit of eight for the `16F877`.


</details>



huangapple
  • 本文由 发表于 2023年6月16日 11:39:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76486827.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定