working semaphore & threading

This commit is contained in:
Olaf Rempel 2008-02-25 18:16:42 +01:00
parent 5a37574a47
commit 021be80589
4 changed files with 151 additions and 18 deletions

View File

@ -47,7 +47,8 @@ struct context {
extern struct context *current_context;
struct context * create_ctx(uint32_t stacksize, uint8_t priority, void (* code)(void *arg), void *arg);
void isr_context_yield(void);
void context_yield(void);
uint8_t isr_context_wait(struct spinlock *lock);
uint8_t context_wait(struct spinlock *lock);
@ -62,4 +63,8 @@ void isr_context_interrupt(struct context *c);
void context_interrupt(struct context *c);
uint32_t context_interrupt_queue(struct context *c, struct context **queue);
struct context * create_ctx(uint32_t stacksize, uint8_t priority, void (* code)(void *arg), void *arg);
void init_context(void);
#endif /* _CONTEXT_H_ */

34
main.c
View File

@ -24,17 +24,25 @@
#include "board.h"
#include "at91_sysc.h"
#include "at91_dbgu.h"
#include "at91_pio.h"
#include "rtos/context.h"
#include "rtos/semaphore.h"
static struct semaphore sem;
void testisr(uint32_t status, uint32_t input)
{
printf("testisr: sem_post()\n\r");
sem_post(&sem);
}
void testfunc(void *p)
{
printf("testfunc: %p\n\r", p);
asm volatile ("swi");
printf("testfunc: %p\n\r", p);
while(1);
while (1) {
printf("testfunc(%ld): sem_wait()\n\r", (uint32_t)p);
sem_wait(&sem);
}
}
int main(void)
@ -47,5 +55,17 @@ int main(void)
at91_dbgu_init();
at91_dbgu_puts("==========================================================\n\rGood morning Dave\n\r");
create_ctx(1024, 0x80, testfunc, 0);
at91_pio_init();
struct context *text_ctx1 = create_ctx(256, 0x80, testfunc, (void *)1);
printf("test_ctx(1)=%p\n\r", text_ctx1);
struct context *text_ctx2 = create_ctx(256, 0x80, testfunc, (void *)2);
printf("test_ctx(2)=%p\n\r", text_ctx2);
sem_init(&sem, 0);
init_context();
}
PIO_PINCHANGE_ISR(TAST1, testisr);

69
src/at91_pio.c Normal file
View File

@ -0,0 +1,69 @@
/***************************************************************************
* Copyright (C) 01/2008 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdint.h>
#include <stdio.h>
#include "AT91SAM7S256.h"
#include "board.h"
#include "at91_pio.h"
/* extern symbols, defined in ldscript */
extern struct pio_pinchange_isr _pio_isr_table;
extern struct pio_pinchange_isr _pio_isr_table_end;
static void pio_isr(void)
{
uint32_t status = *AT91C_PIOA_ISR;
uint32_t input = *AT91C_PIOA_PDSR;
struct pio_pinchange_isr *isr;
for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++)
if (isr->mask & status)
isr->func(status, input);
}
void pio_trigger_isr(uint32_t mask)
{
uint32_t input = *AT91C_PIOA_PDSR;
struct pio_pinchange_isr *isr;
for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++)
if (isr->mask & mask)
isr->func(mask, input);
}
void at91_pio_init(void)
{
/* enable PIO clock */
*AT91C_PMC_PCER = (1 << AT91C_ID_PIOA);
/* enable pinchange interrupts */
struct pio_pinchange_isr *isr;
for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++)
*AT91C_PIOA_IER = isr->mask;
/* dummy read to clear interrupts */
uint32_t dummy = *AT91C_PIOA_ISR;
dummy = dummy;
/* low priority, level triggered, own vector */
AT91S_AIC *aic = AT91C_BASE_AIC;
aic->AIC_SMR[AT91C_ID_PIOA] = IRQPRIO_PIOA | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL;
aic->AIC_SVR[AT91C_ID_PIOA] = (uint32_t)pio_isr;
aic->AIC_IECR = (1 << AT91C_ID_PIOA);
}

View File

@ -45,12 +45,10 @@ __attribute__((naked)) void SWI_Handler(void)
if (current_context != run_queue)
current_context = run_queue;
current_context->state = CONTEXT_RUNNING;
/* restore register context from current_context */
asm volatile (
/* label for first thread creation */
".global __restore_ctx \n\t"
"__restore_ctx: \n\t"
/* get pointer to struct register_context */
"ldr r0, =current_context \n\t"
"ldr r0, [r0] \n\t"
@ -70,6 +68,13 @@ __attribute__((naked)) void SWI_Handler(void)
);
}
static uint8_t isr_context_switch(void)
{
asm volatile ("swi");
// TODO: return previous state of now running thread
return CONTEXT_READY;
}
/* inserts context into run_queue */
static void isr_context_ready(struct context *ctx)
@ -86,14 +91,24 @@ static void isr_context_ready(struct context *ctx)
*qprev = ctx;
}
static uint8_t isr_context_switch(void)
/* process yields, try to switch to process with lower or same prio */
void isr_context_yield(void)
{
// TODO: when called from ISR.. this will go boom :)
asm volatile ("swi");
run_queue = current_context->run_queue;
isr_context_ready(current_context);
return current_context->state;
if (current_context != run_queue) {
current_context->state = CONTEXT_READY;
isr_context_switch();
}
}
void context_yield(void)
{
disable_irqs();
isr_context_yield();
restore_irqs();
}
static uint8_t __isr_context_wait(struct spinlock *lock, uint8_t sleepstate)
{
@ -229,10 +244,13 @@ uint32_t context_interrupt_queue(struct context *c, struct context **queue)
struct context * create_ctx(uint32_t stacksize, uint8_t priority, void (* code)(void *arg), void *arg)
{
void *stack = static_alloc(sizeof(struct context) + stacksize);
uint32_t *stack = static_alloc(sizeof(struct context) + stacksize);
memset(stack, 0, stacksize);
// TODO: check on context-switch for corruption */
stack[0] = 0xdeadbeef;
struct context *ctx = (struct context *)((uint8_t *)stack + stacksize);
ctx->regs.r0 = (uint32_t)arg;
@ -257,9 +275,30 @@ struct context * create_ctx(uint32_t stacksize, uint8_t priority, void (* code)(
ctx->stacksize = stacksize;
ctx->priority = priority;
// TODO: disable irqs?
disable_irqs();
isr_context_ready(ctx);
restore_irqs();
return ctx;
}
void init_context(void)
{
/*
* create shallow idle context
* idle context runs in SVC mode, so no real stack is needed
*/
current_context = create_ctx(4, 255, NULL, NULL);
printf("idle_ctx=%p\n\r", current_context);
/* For now, we're the only thread, so this simply safes our context */
disable_irqs();
isr_context_switch();
restore_irqs();
/* idle loop */
while (1) {
// TODO: this sucks, context switch after interrupt are way better..
context_yield();
}
}