⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os51asm.asm

📁 很好的一个可以在8051上可以运行的ucos
💻 ASM
字号:
;********************************************************************************************************
;                                                 uC/OS
;                                          The Real-Time Kernel
;
;                                   52 SPECIFIC ASSEMBLY LANGUAGE CODE
;
;                                             Rene Voorberg
;                                           80c52 (Large Model)
;				   Using the COMPASS51 compiler from PLC  Texas USA
;
; File : OS51asm.asm
;********************************************************************************************************
;Conventions:
;opt 	:optimized code but is shows you what's happening
;P3.5	:break bit which is used by the Intel Rism Drivers or ROM monitors from 
;PLC to signal a breakpoint. If we are stepping or a breakpoint is hit
;no interrupts should be honoured no more beside the serial interrupt for 
;your debugger.
;_sp	:the (integer) xstackpointer used by the Compass 51 compiler
;_fp	:the (integer) framepointer used by the Compass 51 compiler
;OSTCBCur:
;	Pointer to the current's process OSTCB
;OSTCBHighRdy:
;	Pointer to the process OSTCB with the highest priority which is ready to run
	XDEF  	_OSStartHighRdy
	XDEF  	_OSCtxSw
	XDEF  	_OSIntCtxSw
	XDEF	_OSTickIsr
;I forced OSTCBHighRdy to be near in ucos51.c
	XREF  	_OSTCBHighRdy
;I forced OSTCBCur to be near in ucos51.c
	XREF  	_OSTCBCur
	XREF  	_OSIntExit
	XREF  	_OSIntEnter
	XREF	_OSTimeTick
	XREF	_tick
	XREF	__fp:DATA
	XREF	__sp:DATA
;Extra divisor for slow tick rates
	XREF	_OSTick:DATA
;I forced OSIntNesting to be near in ucos51.c
	XREF	_OSIntNesting:DATA
	XREF	_OSTCBCur:DATA
	XREF	_OSTCBHighRdy:DATA
	XDEF	_RestoreState
;To have the two task pointers run fast we store them near
;The code can also be used with far OSTCBCur and HighRdy 
;then you must remove the next define.
near	EQU	1
;include the appropriate files
INCLUDE "80C320.INC"

;MCS51_CRYSTAL_FREQ   equ 18432000
;OS_TICKS_PER_SEC     equ 20 possible with 80c320 or 80c151
MCS51_CRYSTAL_FREQ   equ 11059200
OS_TICKS_PER_SEC     equ 10

;Determine the reload values for timer 1 this is automated by the next macro
TIMER0RELOAD equ (MCS51_CRYSTAL_FREQ / (OS_TICKS_PER_SEC * 12))
T0RELOADM equ (TIMER0RELOAD>>16)+1	; +1 decause of the djnz instruction which should at least run once 
T0RELOADH equ (65536-(TIMER0RELOAD&65535))>>8
T0RELOADL equ (65536-(TIMER0RELOAD&65535))&255

;Install the interrupt vector for your timer tick in your main program
;In compass we can do it here like:
;    	LVECTOR	00Bh , _OSTickIsr 
	
;The following macro is the assembly code to save the current task's state
;SEGMENT c_text
save_context:	MACRO
	PUSH	PSW
	PUSH	ACC
	PUSH	B
	PUSH	0
	PUSH	1
	PUSH	2
	PUSH	3
	PUSH	4
	PUSH	5
	PUSH	6
	PUSH	7
	PUSH	DPH
	PUSH	DPL
	PUSH	__fp			;save the framepointer (Compass 51)
	PUSH	__fp+1
	PUSH	__sp			;save the stackpointer
	PUSH	__sp+1
	CLR	EA
	;copy internal stack to external
	CLR	C
	MOV	A,SP
	;We intialized every tasks internal stackpointer to 80h
	;in order to determine howe far(near) it has grown we need 
	;to substract 7Fh from the stackpointer
	SUBB	A,#7Fh
	MOV	R1,A		;istacklength in R1
	MOV	R5,A		;also save to move it on top of xstack
	MOV	R0,#80h		;Start address of istack pointer 
	MOV	DPH,__sp	;Get the xstack pointer
	MOV	DPL,__sp+1
	INC	DPTR		;point to the next free location because
				;the xstack pointer points to the last pushed value
$$save_ctx:			;Copy the istack to xstack  
				;(the $$ in the macro is for repetitive macro call labels)
				;compiler generates $1save_ctx first time round and $2 2nd time
	MOV	A,@R0		;Get the byte from the istack
	MOVX	@DPTR,A		;move it into xstack
	INC	DPTR		;advance
	INC	R0		;advance
	DJNZ	R1,$$save_ctx	;Copy the whole internal stack into external stack
	;and adjust _sp
	MOV	A,R5		;Save the istack length onto the xstack
	MOVX	@DPTR,a		;
	INC	DPTR		;__sp should point to the next free byte
	MOV	__sp,DPH	;Save the new stack pointer to __sp
	MOV	__sp+1,DPL
	MOV	SP,#80h		;Start the new task with SP set to #80h
ENDMAC	save_context

restore_context: MACRO	interrupt
	CLR	EA
IFMA 1
;execute this macro with 1 if we have 
;__sp already filled with the appropriate xstack location
;seems difficult but for speedreasons it saves some states.
; this is used in for example an interrupt
;We need to copy __sp in dptr
;	DPTR=_SP
	MOV	DPH,__sp
	MOV	A,__sp+1
ELSE
;enter this macro with dptr loaded with OSTCBCur:
;the new task. We need to copy OSTCBCur->StkPtr in dptr
;	DPTR=_SP=@DPTR 
	MOVX	A,@DPTR
	MOV	R3,A
	INC	DPTR
	MOVX	A,@DPTR
;opt	MOV	DPL,A
	MOV	DPH,R3			;dptr now points to the last free location
ENDIF
;	DPTR-=1
	CLR	C
;opt	MOV	A,DPL
	SUBB	A,#1h			;decrement dptr because it is pointing to the next free xstack position
	MOV	DPL,A
	JNC	$$rest_ctx2
	DEC	DPH			;DPTR now points to the end of the tasks stack
$$rest_ctx2: 
;	A=@DPTR
	MOVX	A,@DPTR			;first byte is number of bytes on external stack
;	DEC	A			;correct that we have read the nr of stacked values
	MOV	R5,A
	CLR	C
	MOV	A,DPL
	SUBB	A,R5			;substract it from the DPTR
	MOV	DPL,A
	JNC	$$rest_ctx3
	DEC	DPH			;DPTR now points to the base of the tasks stack
$$rest_ctx3:
	MOV	R0,#80H			;Every task has its internal stack at IRAM
	MOV	1,5			;Copy nr of bytes on stack in r1
$$rest_ctx4:
	MOVX	A,@DPTR
	MOV	@R0,A
	INC	DPTR
	INC	R0
       	DJNZ	R1,$$rest_ctx4		;Copy the whole stack back into internal stack
	MOV	A,R5			;Copy nr of bytes on stack in A
	ADD	A,#7Fh			;Add 127 for offset for stackpointer not 128 
					;because SP points to a byte that contains data 
					;so 1 byte on stack should be in 80h
	MOV	SP,A			;Restore the stackpointer
	SETB	EA
	LJMP    _RestoreState
ENDMAC	restore_context

;i use this 'function' to return form every interrupt or ctx switch
;it saves space. Interrupts can not enter by a shared routine because the 
;stack can't be fixed to jump to the particular interrupt handler
_RestoreState:
	POP	__sp+1			;Start restoring the context
	POP	__sp			
	POP	__fp+1			
	POP	__fp			
	POP	DPL
	POP	DPH
	POP	7
	POP	6
	POP	5
	POP	4
	POP	3
	POP	2
	POP	1
	POP	0
	POP	B
	POP	ACC
	POP	PSW
	RETI
;*********************************************************************************************************
;                                      START MULTITASKING
;                                   void OSStartHighRdy(void)
;
; Total execution time :  xxbus cycles
;*********************************************************************************************************
_OSStartHighRdy:
	CLR	EA
IFDEF near
;	_OSTCBCur=_OSTCBHighRdy
	MOV	_OSTCBCur,_OSTCBHighRdy
	MOV	_OSTCBCur+1,_OSTCBHighRdy+1
	MOV	DPL,_OSTCBCur+1		;dptr point TO OSTCBCur->STCKPTR 
	MOV	DPH,_OSTCBCur
ELSE
        MOV	DPTR,#(_OSTCBHighRdy)	;R6:R7  = OSTCBHighRdy
	MOVX	A,@DPTR
	MOV	R6,A
	INC	DPTR
	MOVX	A,@DPTR
	MOV	R7,A
	MOV	DPTR,#(_OSTCBCur)	;OSTCBCur = OSTCBHighRdy
	MOV	A,R6
	MOVX	@DPTR,A
	INC	DPTR
	MOV	A,R7
	MOVX	@DPTR,A
	MOV	DPL,R7			;point TO OSTCBCUR->STCKPTR 
	MOV	DPH,R6
ENDIF
	restore_context

;*********************************************************************************************************
;                                PERFORM A CONTEXT SWITCH (From task level)
;                                           void OSCtxSw(void)
;
; Total execution time : xx bus cycles
;*********************************************************************************************************
_OSCtxSw:
	save_context
IFDEF near
;	DPTR=OSTCBCur
	MOV	DPH,_OSTCBCur		;dptr point TO OSTCBCur->STCKPTR 
	MOV	DPL,_OSTCBCur+1
ELSE
;	DPTR=OSTCBCur
        MOV	DPTR,#(_OSTCBCur)	;R6:R7  = OSTCBCur
;	WR6=@DPTR
	MOVX	A,@DPTR
	MOV	R6,A
	INC	DPTR
	MOVX	A,@DPTR
;opt	MOV	R7,A
;	DPTR=WR6
;opt	MOV	DPL,R7			;point TO OSTCNCUR->STCKPTR 
	MOV	DPL,A			;point TO OSTCNCUR->STCKPTR 
	MOV	DPH,R6
ENDIF
;	@DPTR=_SP
	MOV	A,__sp
	MOVX	@DPTR,A
	INC	DPTR
	MOV	A,__sp+1
	MOVX	@DPTR,A
IFDEF near
;	OSTCBCur=OSTCBHighRdy
	MOV	_OSTCBCur,_OSTCBHighRdy
	MOV	_OSTCBCur+1,_OSTCBHighRdy+1
	MOV	DPL,_OSTCBCur+1		;dptr point TO OSTCBCur->STCKPTR 
	MOV	DPH,_OSTCBCur
ELSE
;	DPTR=OSTCBHighRdy
        MOV	DPTR,#(_OSTCBHighRdy)	;get OSTCBHighRdy
;	WR4=@DPTR
	MOVX	A,@DPTR
	MOV	R4,A
	INC	DPTR
	MOVX	A,@DPTR
	MOV	R5,A
;	DPTR=OSTCBCur
        MOV	DPTR,#(_OSTCBCur)	;get OSTCBCur
;	@DPTR=WR4
	MOV	A,R4
	MOVX	@DPTR,A
	INC	DPTR
	MOV	A,R5
	MOVX	@DPTR,A
;	DPTR=WR4
	MOV	DPL,R5			;point TO OSTCNHighRdy->STCKPTR 
	MOV	DPH,R4
ENDIF
	restore_context

_OSIntCtxSw:			;First repair the stackpointer for two calls
	CLR	EA		;Do not interrupt during this sequence
	CLR	C		;copy internal stack to external
	MOV	A,SP
	ADD	A,#-4		;correct 4 bytes on stack for two calls (four bytes)
	MOV	SP,A		;Save the stackpointer
				;On the stack the first two bytes are _sp
				;we need to refresh it because it might have been corrupted
				;in the interrupt routine
				;We pop the _sp into DP because we need it to copy the 
				;internal stack to
	POP	DPL		;
	POP	DPH		;Get the external stack pointer
	PUSH	DPH		;Save it again to keep the stack intact
	PUSH	DPL		;
;	POP	__sp+1		;Optimised
;	POP	__sp		;Start testoring the context
;	PUSH	__sp		;
;	PUSH	__sp+1		;
				;Now copy the internal stack to the external stack
;	CLR	EA		;Do not interrupt during this sequence
				;copy internal stack to external
	CLR	C
;	MOV	A,SP		;Get the stackpointer ;Optimised SP is already in ACC
	SUBB	A,#7Fh		;See how many bytes are on stack
	MOV	R1,A		;Save in R1
	MOV	R5,A		;Save to move on top of xstack
	MOV	R0,#80h		;Bottom of internal stack
;Optimised ;The next section if performed by the POP and PUSH of DP in the previous lines
;	MOV	DPH,__sp	;Get the external stack pointer
;	MOV	DPL,__sp+1
	INC	DPTR		;Point to the next free location
$$save_ctx:
	MOV	A,@R0
	MOVX	@DPTR,A
	INC	DPTR
	INC	R0
	DJNZ	R1,$$save_ctx	;Copy the whole internal stack into external stack
	;and adjust _sp
	MOV	A,R5
	MOVX	@DPTR,a
;	__sp should point to the next free byte
	INC	DPTR
	MOV	__sp,DPH
	MOV	__sp+1,DPL
; Optimised 	MOV	SP,#80h
IFDEF near
;	DPTR=OSTCBCur
	MOV	DPH,_OSTCBCur		;dptr point TO OSTCBCur->STCKPTR 
	MOV	DPL,_OSTCBCur+1
ELSE
;	DPTR=OSTCBCur
        MOV	DPTR,#(_OSTCBCur)	; 4~, R6:R7  = OSTCBCur
;	WR6=@DPTR
	MOVX	A,@DPTR
	MOV	R6,A
	INC	DPTR
	MOVX	A,@DPTR
;opt	MOV	R7,A
;	DPTR=WR6
;opt	MOV	DPL,R7			;point TO OSTCNCUR->STCKPTR 
	MOV	DPL,A			;point TO OSTCNCUR->STCKPTR 
	MOV	DPH,R6
ENDIF
;	@DPTR=_SP
	MOV	A,__sp
	MOVX	@DPTR,A
	INC	DPTR
	MOV	A,__sp+1
	MOVX	@DPTR,A
IFDEF near
;	OSTCBCur=OSTCBHighRdy
	MOV	_OSTCBCur,_OSTCBHighRdy
	MOV	_OSTCBCur+1,_OSTCBHighRdy+1
	MOV	DPL,_OSTCBCur+1		;dptr point TO OSTCBCur->STCKPTR 
	MOV	DPH,_OSTCBCur
ELSE
;	DPTR=OSTCBHighRdy
        MOV	DPTR,#(_OSTCBHighRdy)	; 4~, R6:R7  = OSTCBHighRdy
;	WR4=@DPTR
	MOVX	A,@DPTR
	MOV	R4,A
	INC	DPTR
	MOVX	A,@DPTR
	MOV	R5,A
;	DPTR=OSTCBCur
        MOV	DPTR,#(_OSTCBCur)	; 4~, R6:R7  = OSTCBCur
;	@DPTR=WR4
	MOV	A,R4
	MOVX	@DPTR,A
	INC	DPTR
	MOV	A,R5
	MOVX	@DPTR,A
;	DPTR=WR4
	MOV	DPL,R5			;point TO OSTCBHighRdy->STCKPTR 
	MOV	DPH,R4
ENDIF
	restore_context			;Fix the stack nd return

_OSTickIsr:
        JNB     P3.5,OSTick2		;if break flag set
OSTick1:
	RETI
OSTick2:
	DJNZ	_OSTick,OSTick1
	MOV	_OSTick,#T0RELOADM	;hsb value from macro
	MOV	TL0,#T0RELOADL          ;lsb value set by user
	MOV	TH0,#T0RELOADH 		;m(id)sb value set by user
OSTick3:
	CPL	P1.7			;toggle bit for scope or something
	PUSH	PSW
	PUSH	ACC
	PUSH	B
	PUSH	0
	PUSH	1
	PUSH	2
	PUSH	3
	PUSH	4
	PUSH	5
	PUSH	6
	PUSH	7
	PUSH	DPH
	PUSH	DPL
	PUSH	__fp
	PUSH	__fp+1
	PUSH	__sp
	PUSH	__sp+1
;       LCALL	_OSIntEnter
	INC	_OSIntNesting		;Read modify write increment of OSIntNesting
;	SETB	EA
       	LCALL	_OSTimeTick
;The next instruction shoul only be performed if you get it out of the
;ucos code. Remove OSIntNesting--; from OSIntExit
;This way is faster than the code generated by any compiler
	DEC	_OSIntNesting		;Read modify write increment of OSIntNesting
       	LCALL	_OSIntExit		;Note ! increment of OSIntNesting removed from the UCOS code
	LJMP	_RestoreState		;Use the shared code to exit the interrupt handler


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -