aboutsummaryrefslogtreecommitdiff
path: root/avr/core.S
diff options
context:
space:
mode:
authorOtto Mattik <otto@mattik.org>2021-07-08 18:10:55 +0200
committerOtto Mattik <otto@mattik.org>2021-07-08 18:10:55 +0200
commitda34d97efb21719b2b332f8c60b2750d11bcde1f (patch)
tree2de9fe89f6d79b8ebfcde64c5e86204e904aedf2 /avr/core.S
downloadarmen-1.0.tar.gz
armen-1.0.zip
git: update to v1.0HEADv1.0master
Diffstat (limited to 'avr/core.S')
-rw-r--r--avr/core.S397
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