
;********* ATmega 16 Multitasking 1 ****************** 

.include "m16def.inc"

.equ times = 3000


; ********************* Setting the "times" parameter for a 4 MHz clock frequency *********************
;					 500 = 50 µs (approx.  1:1; 50 % Overhead)
;                   2000 = 450 µs (1:10; 10 % Overhead)
;					3000 = 700 µs (1:14; 6,7 % Overhead)
;                   4000 = 1 ms (1:20; 5 % Overhead)
;                  20000 = 5 ms (1:100; 1 % Overhead)
;

.def temp= r17			; auxiliary registers
.def count= r18
.def die = r19


.DSEG
.ORG 0x0060

CPP: .byte 2
CPA: .byte 2
P1P: .byte 2
P1SP:.byte 2
P2P: .byte 2
P2SP:.byte 2
P3P: .byte 2
P3SP:.byte 2
P4P: .byte 2
P4SP:.byte 2




.ORG ramend-(4*90)
PCA1:		.byte 90
PCA2:		.byte 90
PCA3:		.byte 90
PCA4:		.byte 90

.CSEG

.ORG 0x0000
; 						************************** Interrupttabelle *************************
jmp begin
jmp extint0
jmp extint1
jmp tim2comp
jmp tim2ovf
jmp tim1capt
jmp tim1compa
jmp tim1compb
jmp tim1ovf
jmp tim0ovf
jmp spistc
jmp usartrxc
jmp usartudre
jmp usarttxc
jmp adcrdy
jmp eeready
jmp anacomp
jmp twi
jmp extint2
jmp tim0comp
jmp spmrdy

begin:
	ldi		temp,low(RAMEND) 
	out     SPL,temp        		;init Stack Pointer Low     
	ldi     temp,high(RAMEND)
    out     SPH, temp      			;init Stack Pointer High 

;                  				   Initialize the IO ports

ldi temp,0
out porta,temp
out portb,temp
out portc,temp
out portd, temp
ldi temp,0x7f
out ddra,temp
out ddrb,temp
out ddrc,temp
out ddrd,temp

;                                Initalize the tasks     

ldi r24,low(PCA1) 			; PCA pointer *********** TASK 1
ldi r25,high(PCA1)
sts P1P,r24
sts P1P+1,r25

ldi r24,low(PCA1+88-35) 	; Stack pointer ********* TASK 1
ldi r25,high(PCA1+88-35)
sts P1SP,r24
sts P1SP+1,r25


ldi r24,low(PCA2) 			; PCA pointer *********** TASK 2
ldi r25,high(PCA2)
sts P2P,r24
sts P2P+1,r25

ldi r24,low(PCA2+88-35) 	; Stack pointer ********* TASK 2
ldi r25,high(PCA2+88-35)
sts P2SP,r24
sts P2SP+1,r25


ldi r24,low(PCA3) 			; PCA pointer *********** TASK 3
ldi r25,high(PCA3)
sts P3P,r24
sts P3P+1,r25

ldi r24,low(PCA3+88-35) 	; Stack pointer ********* TASK 3
ldi r25,high(PCA3+88-35)
sts P3SP,r24
sts P3SP+1,r25


ldi r24,low(PCA4) 			; PCA pointer *********** TASK 4
ldi r25,high(PCA4)
sts P4P,r24
sts P4P+1,r25

ldi r24,low(PCA4+88-35) 	; Stack pointer ********* TASK 4
ldi r25,high(PCA4+88-35)
sts P4SP,r24
sts P4SP+1,r25


call tasks_init				; initialize all tasks with the die example program


ldi r24,low(PCA1)  			; Begin with executing the task in partition 1
ldi r25,high(PCA1)
sts CPA,r24
sts CPA+1,r25

ldi r24,low(P1P)
ldi r25,high(P1P) 
sts CPP,r24
sts CPP+1,r25

ldi r24,low(P1SP)
ldi r25,high(P1SP)
out spl,r24			; Set the processor's stack pointer
out sph,r25

	;******************* CTC 1 (Systemzeitgeber)

ldi temp, high (times)
out ocr1ah,temp
ldi temp, low(times)
out ocr1al, temp
ldi temp,0x09					; CTC 1 auf Normal Mode; 1:1 Takt
out tccr1b,temp 				; Clear on Compare Match A
ldi temp,0x10
out timsk,temp					; Compare Match A Interrupt
rjmp breakout  					; Start with the selected task ************* Interrupt will be armed *************

iwait:							; Wait for the first timer interrupt
rjmp iwait





;**************** Interrupt Handlers ****************************

extint0:

extint1:

tim2comp:

tim2ovf:

tim1capt:

tim1compa:

rjmp timeslice

tim1compb:

tim1ovf:

tim0ovf:

spistc:

usartrxc:

usartudre:

usarttxc:

adcrdy:

eeready:

anacomp:

twi:

extint2:

tim0comp:

spmrdy:



; 	******************************************************************************************
;	******************************************************************************************

;  Interrupt / System Call
brk:
cli				; disable the interrupts

timeslice:
sbi porta,0  ; ### Set the auxiliary pulse for measuring the time slice. Remove if not necessary
push r31
push r30
push r29
push r28
push r27
push r26
push r25
push r24
push r23
push r22
push r21
push r20
push r19
push r18
push r17
push r16
push r15
push r14
push r13
push r12
push r11
push r10
push r9
push r8
push r7
push r6
push r5
push r4
push r3
push r2
push r1
push r0
in temp,sreg
push temp


; -----------------------------------------------


lds yl,CPP			; Current partition pointer to y-register
lds yh,CPP+1

in r24,spl			; fetch the content of the processor's stack pointer 
in r25,sph

std y+2,r24			; Store the stack pointer in the PCA
std y+3,r25


adiw yl,4			; Increment the Current partition pointer
cpi yl,low(P4P+4)   ; Does exceed the P4P address?	
brne nexttask		; No	
cpi yh, high(P4P+4)
brne nexttask

firsttask:			; Yes. Proceed with partition 1
ldi yl,low(P1P)
ldi yh,high(P1P)

nexttask:
sts CPP,yl
sts CPP+1,yh 		; Set the new Current partition pointer



;          ********************* Breakout. Proceed with the next task ******************
breakout:
lds yl,CPP			; Current partition pointer to y-register
lds yh,CPP+1

ldd r24,y+0			; Fetch the partition's PCA pointer and make it to the Current PCA pointer 
ldd r25,y+1
sts CPA,r24
sts CPA+1,r25

ldd r24,y+2			; Fetch the partition's SP 
ldd r25,y+3

out spl,r24			; Set the processor's stack pointer
out sph,r25

; --------------------------------------------------


pop temp
andi temp,0x7f			; Clear the Interrupt Enable Flag
out sreg,temp			; load te flag (status) register
pop r0
pop r1
pop r2
pop r3
pop r4
pop r5
pop r6
pop r7
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
pop r16
pop r17
pop r18
pop r19
pop r20
pop r21
pop r22
pop r23
pop r24
pop r25
pop r26
pop r27
pop r28
pop r29
pop r30
pop r31
cbi porta,0   	; ### Clear the auxiliary pulse for measuring the time slice. Remove if not necessary
reti				; Now, the next task will run

; ***************************************************************************************

; Initialize the tasks with the die example


Tasks_init:

ldi r24,0x39						; virtual port adrs
sts PCA1,r24

ldi r24,low(init_1)					; Instruction counter
ldi r25,high(init_1)
sts PCA1+87,r25
sts PCA1+88,r24


ldi r24,0x36						; virtual port adrs
sts PCA2,r24

ldi r24,low(init_2) 				; Instruction counter
ldi r25,high(init_2)
sts PCA2+87,r25
sts PCA2+88,r24


ldi r24,0x33						; virtual port adrs
sts PCA3,r24

ldi r24,low(init_3) 				; Instruction counter
ldi r25,high(init_3)
sts PCA3+87,r25
sts PCA3+88,r24


ldi r24,0x30						; virtual port adrs
sts PCA4,r24

ldi r24,low(init_4) 				; Instruction counter
ldi r25,high(init_4)
sts PCA4+87,r25
sts PCA4+88,r24

ret



; ******************* The programs to be run in each task ********

; Here, it is always the die example

init_1:
jmp die_ex

;***************************************************************

init_2:
jmp die_ex

;**************************************************************

init_3:
jmp die_ex

; **************************************************************

init_4:
jmp die_ex


; **************************************************************


; ********************** The die example ***********************

die_ex:

lds yl,CPA
lds yh,CPA+1

ldd zl,y+0  ; the virtual port address
ldi zh,0

die_loop:
ldi die,1    ; begin to count from 1		

diedisplay:
mov temp,die
rcall convseg
std z+2,r0

diewait:
ldd r16,z+0
andi r16,0x80
brne diewait

inc die
cpi die,7
brne diedisplay

rjmp die_loop

; *******************  Subroutines

convseg:
push zl
push zh						;number in temp
ldi zl,low(segtab*2)
ldi zh, high(segtab*2)
add zl,temp
ldi temp,0
adc zh,temp
lpm
pop zh
pop zl
ret


; The seven-segment pattern table
segtab:
.db 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90



