diff options
| author | Otto Mattik <otto@mattik.org> | 2021-07-08 18:10:55 +0200 |
|---|---|---|
| committer | Otto Mattik <otto@mattik.org> | 2021-07-08 18:10:55 +0200 |
| commit | da34d97efb21719b2b332f8c60b2750d11bcde1f (patch) | |
| tree | 2de9fe89f6d79b8ebfcde64c5e86204e904aedf2 /avr/core.S | |
| download | armen-1.0.tar.gz armen-1.0.zip | |
Diffstat (limited to 'avr/core.S')
| -rw-r--r-- | avr/core.S | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/avr/core.S b/avr/core.S new file mode 100644 index 0000000..da35058 --- /dev/null +++ b/avr/core.S @@ -0,0 +1,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 |
