1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
|
/************************************************************************/
/* */
/* File: avr/core.s */
/* Description: cpu dependent (or optimized) part of kernel */
/* Version: 1.0 */
/* Author: Otto Mattik */
/* */
/* (C)Copyright Otto Mattik 2014-2021. */
/* */
/* This file is a part of 'armen' (a tiny operating system). */
/* 'armen' is distributed under the CeCILL-V2.1 licence. For more */
/* details about this licence, please visit the website cecill.info */
/* */
/************************************************************************/
#ifndef F_CPU
#error "cpu clock frequency is not defined"
#endif
#if (F_CPU == 16000000UL)
#define CLOCK_PRESCALE 3
#define CLOCK_TICKS 250
#elif (F_CPU == 12000000UL)
#define CLOCK_PRESCALE 3
#define CLOCK_TICKS 187
#elif (F_CPU == 8000000UL)
#define CLOCK_PRESCALE 3
#define CLOCK_TICKS 125
#elif (F_CPU == 4000000UL)
#define CLOCK_PRESCALE 3
#define CLOCK_TICKS 62
#else
#error "no parameters for the clock frequency"
#endif
#define SPH 0x3E
#define SPL 0x3D
#define SREG 0x3F
#include <avr/io.h>
#ifdef __AVR_HAVE_JMP_CALL__
#define JMP jmp
#define CALL call
#else
#define JMP rjmp
#define CALL rcall
#endif
.text
/*
* here we go ...
* in:
* out:
*/
.global armen_start
armen_start:
cli
/*
* initialize timer 0 to 1kHz (timer 1 if tiny85)
*/
#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny85V__)
ldi r24, _BV(CTC1)|_BV(CS13)|CLOCK_PRESCALE
sts TCCR1, r24 ; CTC mode + prescaler
ldi r24, CLOCK_TICKS
sts OCR1A, r24 ; counter A
ldi r24, _BV(OCIE1A)
sts TIMSK, r24 ; enable comparator
#else
ldi r24, _BV(WGM01)
sts TCCR0A, r24 ; CTC mode
ldi r24, CLOCK_PRESCALE
sts TCCR0B, r24 ; prescaler
ldi r24, CLOCK_TICKS
sts OCR0A, r24 ; counter A
ldi r24, _BV(OCIE0A)
#ifdef TIMSK
sts TIMSK, r24 ; enable comparator
#else
sts TIMSK0, r24 ; enable comparator
#endif
#endif
/*
* initialize the os
*/
ldi r23, hi8(RAMEND)
ldi r22, lo8(RAMEND) ; arg2 = end of ram (stack)
ldi r25, hi8(__bss_end)
ldi r24, lo8(__bss_end) ; arg1 = end of bss (heap)
CALL _sys_init ; see core.c
sei
ret
/*
* clock (1 ms)
* in:
* out:
*/
.global TIMER0_COMPA_vect
TIMER0_COMPA_vect:
CALL _save_context
push r24
push r25
CALL _sys_clock ; see core.c
pop r25
pop r24
.L1:
CALL _scheduler
.L2:
/*
* restore context
*/
pop r0
out SREG, r0
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
reti ; works well because is same as ret (for stack)
; differ only in global interrupt flag
/*
* call the scheduler
* in:
* out:
*/
.global _schedule
_schedule:
CALL _save_context
JMP .L1
/*
* set initial thread context
* in:
* r24/r25 entry point (WARNING: must be in first flash 128 kb)
* r22/r23 thread call parameter
* r20/r21 stack pointer
* out:
* new SP
*/
.global _init_context
_init_context:
push ZH
push ZL
push r17
push r16
ldi r16, 33 ; size for all general + SREG registers
#ifdef __AVR_3_BYTE_PC__
subi r20, 38
#else
subi r20, 36 ; add 2 PC size for ret(i) and _thread_exit
#endif
sbci r21, 0
mov ZH, r21
mov ZL, r20 ; top of new stack
clr r17
.L3:
st Z+, r17 ; set all registers to 0
subi r16, 1
brne .L3
#ifdef __AVR_3_BYTE_PC__
st Z+, r17
#endif
st Z+, r25
st Z+, r24 ; entry point for ret(i)
ldi r25, hi8(_thread_exit)
ldi r24, lo8(_thread_exit)
#ifdef __AVR_3_BYTE_PC__
st Z+, r17
#endif
st Z+, r25
st Z+, r24 ; entry point for _thread_exit
cpi r22, 0
cpc r23, r17
breq .L4
mov ZH, r21
mov ZL, r20
std Z+24, r22
std Z+25, r23 ; set parameter in r24/r25 location
.L4:
mov r25, r21
mov r24, r20
subi r24, 1
sbci r25, 0 ; new SP value
pop r16
pop r17
pop ZL
pop ZH
ret
/*
* save all general + SREG registers
* in:
* out:
* new SP
*/
.global _save_context
_save_context:
#ifdef __AVR_3_BYTE_PC__
pop r1 ; bits 17-22 of PC
#endif
push YH
push YL
push r27
push r26
push r25 ; registers sets in the right place
in r25, SREG ; save SREG
in YH, SPH
in YL, SPL
adiw YL, 6
ld r27, Y+
ld r26, Y+ ; save PC for return
st -Y, r31
st -Y, r30 ; set Z instead of PC in stack
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
#ifdef __AVR_3_BYTE_PC__
clr r2
push r2
#else
push r1
#endif
push r0
push r25 ; store SREG
in r25, SPH
in r24, SPL ; return new SP
push r26
push r27 ; restore PC (context: 32+1+(2|3) bytes)
#ifdef __AVR_3_BYTE_PC__
push r1
#endif
ret
/*
* switch thread context (called by scheduler)
* in:
* r24/r25 new stack pointer
* out:
* no return
*/
.global _restore_context
_restore_context:
#ifdef __AVR_3_BYTE_PC__
pop r0
pop r0
#endif
pop r0
pop r0 ; PC stacked at _restore_context call
pop r0
pop r0 ; PC stacked at _scheduler call
out SPH, r25
out SPL, r24
JMP .L2
/*
* disable interruptions
* in:
* out:
* interruption flag
*/
.global _disable_intr
_disable_intr:
in r24, SREG
cli
andi r24, 0x80
ret
/*
* enable interruptions
* in:
* r24 interruption flag
* out:
*/
.global _enable_intr
_enable_intr:
cpi r24, 0
breq .L5
sei
.L5:
ret
/*
* delay loops
* in:
* r24/r25 count of microseconds
* out:
*/
.global delay
delay:
#if (F_CPU > 12000000UL)
nop
nop
nop
nop ; 4 cycles
#endif
#if (F_CPU > 8000000UL)
nop
nop
nop
nop ; 4 cycles
#endif
#if (F_CPU > 4000000UL)
nop
nop
nop
nop ; 4 cycles
#endif
sbiw r24, 1 ; 2 cycles
brne delay ; 2 cycles or 1 if false
ret
/*
* this thread is elected when all others are suspend
* it do nothing (set cpu in sleep mode ???)
* in:
* out:
*/
.global _idle
_idle:
rjmp _idle
/*
* test and set a mutex (atomic operation)
* in:
* r24/r25 address of mutex (byte)
* out:
* previous state of mutex
*/
.global test_and_set
test_and_set:
push ZH
push ZL
mov ZH, r25
mov ZL, r24
#ifdef XMEGA
ldi r24, 1
xch Z, r24
#else
ldi r25, 1
cli
ld r24, Z
st Z, r25
sei
#endif
pop ZL
pop ZH
ret ; r24 = previous state of mutex
|