1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2025-01-30 21:11:06 +02:00

make lcd almost work

This commit is contained in:
Bas Wijnen 2009-07-05 10:52:44 +02:00
parent eb141d7901
commit 4b47df85e3
11 changed files with 194 additions and 174 deletions

View File

@ -179,7 +179,7 @@ Thread *Memory::alloc_thread ():
ret->pc = 0 ret->pc = 0
ret->sp = 0 ret->sp = 0
Thread_arch_init (ret) Thread_arch_init (ret)
ret->sleep = 0 ret->sleep_count = ~0
ret->flags = 0 ret->flags = 0
ret->schedule_prev = NULL ret->schedule_prev = NULL
ret->schedule_next = NULL ret->schedule_next = NULL

View File

@ -37,97 +37,53 @@ static void set_backlight (bool state):
PWM_CTR (0) = 0x3f PWM_CTR (0) = 0x3f
GPIO_GPDR (2) &= ~PWM_ENABLE GPIO_GPDR (2) &= ~PWM_ENABLE
// Write to a register. Value must be in range [0, 0xff].
static void write_reg (unsigned reg, unsigned value):
unsigned data = (reg << 0xa) | 0x200 | value
GPIO_GPDR (2) |= SPEN
GPIO_GPDR (2) = (GPIO_GPDR (2) & ~SPDA) | SPCK
GPIO_GPDR (2) &= ~SPEN
udelay(25)
for unsigned i = 0; i < 16; ++i:
GPIO_GPDR (2) &= ~SPCK
if data & 0x8000:
GPIO_GPDR (2) |= SPDA
else:
GPIO_GPDR (2) &= ~SPDA
udelay (25)
GPIO_GPDR (2) |= SPCK
udelay (25)
data <<= 1
GPIO_GPDR (2) |= SPEN
udelay(200)
static void lcd_enable ():
udelay (50)
GPIO_GPDR (2) &= ~LCD_RET
udelay(150000)
GPIO_GPDR (2) |= LCD_RET
udelay(10000)
// These values have been copied from the linux source.
// I have no idea what they do.
write_reg (0x00, 0x03)
write_reg (0x01, 0x40)
write_reg (0x02, 0x11)
write_reg (0x03, 0xcd)
write_reg (0x04, 0x32)
write_reg (0x05, 0x0e)
write_reg (0x07, 0x03)
write_reg (0x08, 0x08)
write_reg (0x09, 0x32)
write_reg (0x0A, 0x88)
write_reg (0x0B, 0xc6)
write_reg (0x0C, 0x20)
write_reg (0x0D, 0x20)
set_backlight (true)
static void lcd_disable ():
write_reg (0x00, 0x03)
set_backlight (false)
static void reset (): static void reset ():
gpio_as_pwm ()
gpio_as_lcd_master ()
GPIO_GPDR (2) &= ~PWM_ENABLE
PWM_CTR (0) = 0x3f
PWM_PER (0) = 300 PWM_PER (0) = 300
pwm_set_duty (0, 300) set_backlight (false)
pwm_set_full_duty (0)
// initialize things. // initialize things.
GPIO_GPIER (2) &= ~(PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA) GPIO_GPIER (2) &= ~(PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA)
GPIO_GPDIR (2) |= PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA GPIO_GPDIR (2) |= PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA
udelay (50) udelay (50)
GPIO_GPDR (2) &= ~LCD_RET GPIO_GPDR (2) &= ~LCD_RET
udelay (150000) ddelay (2)
GPIO_GPDR (2) |= LCD_RET GPIO_GPDR (2) |= LCD_RET
udelay (10000) ddelay (1)
lcd_enable ()
// For now, support only 16 bpp. // For now, support only 16 bpp.
// Screen is 800x480 tft. // Screen is 800x480 tft.
unsigned h = 800, v = 480, hs = 80, vs = 20, fps = 60, Bpp = 2
LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16 LCD_CTRL = LCD_CTRL_BPP_16 | LCD_CTRL_BST_16
LCD_VSYNC = 20 LCD_VSYNC = vs
LCD_HSYNC = 80 LCD_HSYNC = hs
LCD_DAV = (20 << 16) | 500 LCD_DAV = (vs << 16) | (vs + v)
LCD_DAH = (80 << 16) | 880 LCD_DAH = (hs << 16) | (hs + h)
LCD_VAT = (880 << 16) | 500 LCD_VAT = ((hs + h) << 16) | (vs + v)
//LCD_CFG = MODE_TFT_GEN | PCLK_N | VSYNC_N #define MODE_TFT_GEN 0
#define PCLK_N (1 << 10)
#define VSYNC_N (1 << 8)
LCD_CFG = MODE_TFT_GEN | PCLK_N | VSYNC_N
// Stop lcd. cpm_stop_lcd ()
CPM_MSCR |= 1 << 7
unsigned pclk = 60 * (800 * 3 + 80) * 500
unsigned pllout = cpm_get_pllout () unsigned pllout = cpm_get_pllout ()
CPM_CFCR2 = pllout / pclk - 1 unsigned pixclock = fps * (hs + h) * (vs + v)
unsigned v = pllout / (pclk * 4) - 1 CPM_CFCR2 = pllout / pixclock - 1
while v < 0xf && pllout / (v + 1) > 150000000:
++v unsigned val = pllout / (pixclock * 4) - 1
CPM_CFCR = (CPM_CFCR & ~CPM_CFCR_LFR_MASK) | (v << CPM_CFCR_LFR_BIT) | CPM_CFCR_UPE while val < 0xf && pllout / (val + 1) > 150000000:
++val
cpm_set_lcdclk_div (val)
CPM_CFCR |= CPM_CFCR_UPE
cpm_start_lcd ()
// Start lcd.
CPM_MSCR &= ~(1 << 7)
udelay (1000) udelay (1000)
//LCD_DA0 = framebuffer
unsigned frame_size = v * h * Bpp
LCD_CMD0 = LCD_CMD_SOFINT | LCD_CMD_EOFINT | (frame_size << LCD_CMD_LEN_BIT)
lcd_set_ena ()
lcd_enable_eof_intr ()
int main (): int main ():
map_gpio () map_gpio ()
@ -136,19 +92,20 @@ int main ():
map_cpm () map_cpm ()
reset () reset ()
register_interrupt (IRQ_LCD)
while true: set_backlight (true)
set_backlight (false)
kdebug (0)
set_backlight (true)
kdebug (0)
schedule ()
while true: while true:
Message msg Message msg
if !wait (&msg): if !wait (&msg):
continue continue
switch msg.protected_data: switch msg.protected_data:
case IRQ_LCD:
kdebug (0)
LCD_STATE &= ~LCD_STATE_EOF
register_interrupt (IRQ_LCD)
// TODO: allow callback
break
case LCD_BACKLIGHT: case LCD_BACKLIGHT:
set_backlight (msg.data[0]) set_backlight (msg.data[0])
break break

View File

@ -18,6 +18,7 @@
#include "kernel.hh" #include "kernel.hh"
// From user-provided, thus untrusted, data, find a capability.
Capability *Memory::find_capability (unsigned code, bool *copy): Capability *Memory::find_capability (unsigned code, bool *copy):
if !code: if !code:
return NULL return NULL
@ -39,6 +40,7 @@ Capability *Memory::find_capability (unsigned code, bool *copy):
return c return c
return NULL return NULL
// Try to deliver a message.
bool Receiver::try_deliver (): bool Receiver::try_deliver ():
if !messages || !owner || !owner->is_waiting (): if !messages || !owner || !owner->is_waiting ():
return false return false
@ -61,6 +63,7 @@ bool Receiver::try_deliver ():
owner->unwait () owner->unwait ()
return true return true
// Send a message to a receiver; try to deliver it immediately.
bool Receiver::send_message (unsigned protected_data, Capability::Context *c): bool Receiver::send_message (unsigned protected_data, Capability::Context *c):
bool tried_direct = false bool tried_direct = false
if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only): if owner && owner->is_waiting () && (protected_data == reply_protected_data || !protected_only):
@ -328,14 +331,19 @@ static void thread_invoke (unsigned target, unsigned protected_data, Capability:
thread->unrun () thread->unrun ()
break break
case CAP_THREAD_INFO_SLEEP: case CAP_THREAD_INFO_SLEEP:
value = &thread->sleep value = &thread->sleep_count
if thread->flags & THREAD_FLAG_WAITING:
unsigned newval = (*value & ~c->data[3]) | (c->data[2] & c->data[3])
if *value == ~0 && newval != ~0:
thread->sleep ()
else if *value != ~0 && newval == ~0:
thread->unsleep ()
break break
default: default:
value = Thread_arch_info (thread, c->data[1]) value = Thread_arch_info (thread, c->data[1])
break break
if value: if value:
*value &= ~c->data[3] *value = (*value & ~c->data[3]) | (c->data[2] & c->data[3])
*value |= c->data[2] & c->data[3]
reply_num (*value) reply_num (*value)
else: else:
reply_num (0) reply_num (0)
@ -655,19 +663,19 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, Capability:
reply_receiver = (Receiver *)protected_data reply_receiver = (Receiver *)protected_data
reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC)) reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC))
Capability *c0 = c->cap[0] Capability *c0 = c->cap[0]
if ((unsigned)c0->target & ~KERNEL_MASK) != 0: if c0:
Capability r if ((unsigned)c0->target & ~KERNEL_MASK) != 0:
fill_cap (&r, protected_data, reply_receiver->reply_protected_data) Capability r
c->cap[0] = &r fill_cap (&r, protected_data, reply_receiver->reply_protected_data)
c->copy[0] = true c->cap[0] = &r
c0->target->send_message (c0->protected_data, c) c->copy[0] = true
r.invalidate () c0->target->send_message (c0->protected_data, c)
return true r.invalidate ()
else: else:
// Kernel call: don't create actual capablities. // Kernel call: don't create actual capablities.
c->cap[0] = NULL c->cap[0] = NULL
kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0) kernel_invoke ((unsigned)c0->target, c0->protected_data, c, c0)
return true return true
if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)): if (target & (CAPTYPE_MASK | (1 << CAP_RECEIVER_REPLY))) == (CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_REPLY)):
// This is a reply capability. // This is a reply capability.
Receiver *r = (Receiver *)protected_data Receiver *r = (Receiver *)protected_data
@ -717,4 +725,5 @@ bool Capability::invoke (Capability::Context *c):
// This is not a kernel capability: send a message to the receiver. // This is not a kernel capability: send a message to the receiver.
return target->send_message (protected_data, c) return target->send_message (protected_data, c)
// This is a kernel capability. Use a function to allow optimized call capabilities. // This is a kernel capability. Use a function to allow optimized call capabilities.
reply_receiver = NULL
return kernel_invoke ((unsigned)target, protected_data, c, this) return kernel_invoke ((unsigned)target, protected_data, c, this)

19
iris.h
View File

@ -18,6 +18,13 @@
#ifndef __IRIS_H #ifndef __IRIS_H
#define __IRIS_H #define __IRIS_H
// Without the standard library, we don't have this definition.
// I preferred ((void*)0), but C++ has too strict type-checking to
// make that work.
#ifndef NULL
#define NULL 0
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -501,9 +508,17 @@ static unsigned thread_sleep (Capability thread, unsigned value)
return thread_info (thread, CAP_THREAD_INFO_SLEEP, value, ~0); return thread_info (thread, CAP_THREAD_INFO_SLEEP, value, ~0);
} }
static void my_sleep (unsigned value) static int my_sleep (unsigned value, Message *ret)
{ {
call_n04 (__my_thread, CAP_THREAD_INFO, CAP_THREAD_INFO_SLEEP, value, ~0); ret->data[0] = CAP_THREAD_INFO;
ret->data[1] = CAP_THREAD_INFO_SLEEP;
ret->data[2] = value;
ret->data[3] = ~0;
ret->cap[0] = 0;
ret->cap[1] = 0;
ret->cap[2] = 0;
ret->cap[3] = 0;
return call (__my_thread, ret);
} }
static unsigned thread_get_sleep (Capability thread) static unsigned thread_get_sleep (Capability thread)

View File

@ -33,11 +33,6 @@
#define EXTERN extern #define EXTERN extern
#endif #endif
// Without the standard library, we don't have this definition.
// I preferred ((void*)0), but C++ has too strict type-checking to
// make that work.
#define NULL 0
struct Object_base struct Object_base
struct Page struct Page
struct Thread struct Thread
@ -73,8 +68,10 @@ struct Thread : public Object <Thread>:
unsigned pc, sp unsigned pc, sp
Thread_arch arch Thread_arch arch
unsigned flags unsigned flags
unsigned sleep unsigned sleep_count
Thread *schedule_prev, *schedule_next Thread *schedule_prev, *schedule_next
void sleep ()
void unsleep ()
void run () void run ()
void unrun () void unrun ()
void wait () void wait ()

View File

@ -111,9 +111,6 @@ start_idle: // 280
// Wait for the next interrupt, then the first thread will be scheduled. // Wait for the next interrupt, then the first thread will be scheduled.
// It is impractical to try to call schedule, because for that the // It is impractical to try to call schedule, because for that the
// idle task would need to own capabilities. // idle task would need to own capabilities.
move $v0, $zero
syscall
nop
1: wait 1: wait
b 1b b 1b
nop nop
@ -221,7 +218,8 @@ save_regs:
#ifndef NDEBUG #ifndef NDEBUG
// Allow interrupts to set EPC and friends. // Allow interrupts to set EPC and friends.
mfc0 $k0, $CP0_STATUS mfc0 $k0, $CP0_STATUS
andi $k0, $k0, 0xff00 li $k1, 0x1000ff00
and $k0, $k0, $k1
mtc0 $k0, $CP0_STATUS mtc0 $k0, $CP0_STATUS
#endif #endif

View File

@ -257,12 +257,14 @@ void init ():
GPIO_GPDIR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN GPIO_GPDIR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN
GPIO_GPDR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN GPIO_GPDR (GPIO_USB_CLK_EN_PORT) |= 1 << GPIO_USB_CLK_EN
// Start the operating system timer. // Start the operating system timer, and set it to give an interrupt immediately.
unsigned latch = (JZ_EXTAL + (HZ>>1)) / HZ // This is better, because the kernel start with jumping into the idle task and
// waiting for the first interrupt.
unsigned latch = (JZ_EXTAL + (HZ >> 1)) / HZ
ost_disable_all () ost_disable_all ()
ost_set_mode (0, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL) ost_set_mode (0, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL)
ost_set_reload (0, latch) ost_set_reload (0, latch)
ost_set_count (0, latch) ost_set_count (0, 0)
ost_set_mode (0, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL) ost_set_mode (0, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL)
ost_enable_channel (0) ost_enable_channel (0)
intc_unmask_irq (IRQ_OST0) intc_unmask_irq (IRQ_OST0)

View File

@ -19,11 +19,40 @@
#define ARCH #define ARCH
#include "../kernel.hh" #include "../kernel.hh"
static void handle_exit (Thread *old_current):
if !current:
schedule ()
if !current:
current = &idle
if old_current == current:
return
if current != &idle:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]:
current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
else:
static unsigned random = 1
current->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
++random
if random >= 64:
random = 1
asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory
if current->flags & THREAD_FLAG_PRIV:
cp0_set (CP0_STATUS, 0x1000ff13)
else:
cp0_set (CP0_STATUS, 0x0000ff13)
/// A TLB miss has occurred. This is the slow version. It is only used /// A TLB miss has occurred. This is the slow version. It is only used
/// when k0 or k1 is not 0, or when an error occurs. /// when k0 or k1 is not 0, or when an error occurs.
/// Otherwise, the ultra-fast code in entry.S is used. /// Otherwise, the ultra-fast code in entry.S is used.
Thread *tlb_refill (): Thread *tlb_refill ():
//panic (0x88776655, "TLB refill") //panic (0x88776655, "TLB refill")
Thread *old_current = current
if !directory: if !directory:
panic (0x44449999, "No directory") panic (0x44449999, "No directory")
unsigned EntryHi unsigned EntryHi
@ -41,11 +70,13 @@ Thread *tlb_refill ():
cp0_set (CP0_ENTRY_LO0, t[idx]) cp0_set (CP0_ENTRY_LO0, t[idx])
cp0_set (CP0_ENTRY_LO1, t[idx + 1]) cp0_set (CP0_ENTRY_LO1, t[idx + 1])
__asm__ volatile ("tlbwr") __asm__ volatile ("tlbwr")
handle_exit (old_current)
return current return current
/// An interrupt which is not an exception has occurred. /// An interrupt which is not an exception has occurred.
Thread *interrupt (): Thread *interrupt ():
//panic (0x88877722, "Interrupt") //panic (0x88877722, "Interrupt")
Thread *old_current = current
//dbg_send (INTC_IPR) //dbg_send (INTC_IPR)
unsigned ipr = INTC_IPR unsigned ipr = INTC_IPR
for unsigned i = 0; i < 32; ++i: for unsigned i = 0; i < 32; ++i:
@ -68,6 +99,7 @@ Thread *interrupt ():
ost_clear_uf (0) ost_clear_uf (0)
intc_ack_irq (IRQ_OST0) intc_ack_irq (IRQ_OST0)
timer_interrupt () timer_interrupt ()
handle_exit (old_current)
return current return current
void flush_tlb (unsigned asid): void flush_tlb (unsigned asid):
@ -87,10 +119,9 @@ static void arch_invoke ():
Thread *caller = current Thread *caller = current
target = caller->address_space->find_capability (caller->arch.v0, &wait) target = caller->address_space->find_capability (caller->arch.v0, &wait)
if !target: if !target:
// TODO: there must be no action here. This is just because the rest doesn't work yet. // There must be no action here.
dbg_send (3, 2) //dbg_send (3, 2)
//dbg_send (caller->arch.v0) //dbg_send (caller->arch.v0)
schedule ()
// Calling an invalid capability always fails. // Calling an invalid capability always fails.
caller->arch.v0 = 0 caller->arch.v0 = 0
else: else:
@ -108,35 +139,10 @@ static void arch_invoke ():
caller->arch.v0 = target->invoke (&c) ? 1 : 0 caller->arch.v0 = target->invoke (&c) ? 1 : 0
if caller != current && caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING: if caller != current && caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING:
current = caller current = caller
else if !current:
schedule ()
if !current:
current = &idle
if caller != current:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]:
current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
else:
static unsigned random = 1
current->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
++random
if random >= 64:
random = 1
asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory
unsigned status
cp0_get (CP0_STATUS, status)
status &= 0x0fffffff
if current->flags & THREAD_FLAG_PRIV:
status |= 0x10000000
cp0_set (CP0_STATUS, status | 0x13)
/// A general exception has occurred. /// A general exception has occurred.
Thread *exception (): Thread *exception ():
Thread *old_current = current
unsigned cause unsigned cause
cp0_get (CP0_CAUSE, cause) cp0_get (CP0_CAUSE, cause)
switch (cause >> 2) & 0x1f: switch (cause >> 2) & 0x1f:
@ -220,9 +226,12 @@ Thread *exception ():
panic (0xf5223344, "Reserved exception code") panic (0xf5223344, "Reserved exception code")
default: default:
panic (0xf6223344, "Impossible exception code") panic (0xf6223344, "Impossible exception code")
handle_exit (old_current)
return current return current
/// There's a cache error. Big trouble. Probably not worth trying to recover. /// There's a cache error. Big trouble. Probably not worth trying to recover.
Thread *cache_error (): Thread *cache_error ():
panic (0x33333333, "cache error") panic (0x33333333, "cache error")
Thread *old_current = current
handle_exit (old_current)
return current return current

View File

@ -23,6 +23,7 @@
// Main clock, for cpu, serial port, and with divisors for most other hardware // Main clock, for cpu, serial port, and with divisors for most other hardware
#define JZ_EXTAL 3686400 #define JZ_EXTAL 3686400
//#define JZ_EXTAL 3072000
// RTC clock // RTC clock
#define RTC_CLOCK 32768 #define RTC_CLOCK 32768
@ -2311,8 +2312,9 @@ static __inline__ void udelay (unsigned us):
GPIO_GPDR (0) = GPIO_GPDR (0) GPIO_GPDR (0) = GPIO_GPDR (0)
#ifndef __KERNEL #ifndef __KERNEL
static __inline__ void mdelay (unsigned ms): static __inline__ void ddelay (unsigned ds):
my_sleep ((ms + 99) / 100) Message m
my_sleep (ds, &m)
#endif #endif
/*************************************************************************** /***************************************************************************

View File

@ -109,6 +109,6 @@ void dbg_send (unsigned code, unsigned bits):
dbg_led (false, false, false) dbg_led (false, false, false)
dbg_sleep (200) dbg_sleep (200)
dbg_led (true, true, false) dbg_led (true, true, false)
dbg_sleep (500) dbg_sleep (50)
dbg_led (false, false, false) dbg_led (false, false, false)
dbg_sleep (500) dbg_sleep (50)

View File

@ -33,18 +33,29 @@ static void unrun_thread (Thread *thread):
first_scheduled = thread->schedule_next first_scheduled = thread->schedule_next
if thread->schedule_next: if thread->schedule_next:
thread->schedule_next->schedule_prev = thread->schedule_prev thread->schedule_next->schedule_prev = thread->schedule_prev
if thread->sleep:
thread->schedule_next = first_sleeper void Thread::sleep ():
thread->schedule_prev = NULL schedule_next = first_sleeper
if thread->schedule_next: if schedule_next:
thread->schedule_next->schedule_prev = thread schedule_next->schedule_prev = this
first_sleeper = thread schedule_prev = NULL
first_sleeper = this
void Thread::unsleep ():
if schedule_next:
schedule_next->schedule_prev = schedule_prev
if schedule_prev:
schedule_prev->schedule_next = schedule_next
else:
first_sleeper = schedule_next
void Thread::run (): void Thread::run ():
if flags & THREAD_FLAG_RUNNING: if flags & THREAD_FLAG_RUNNING:
return return
flags |= THREAD_FLAG_RUNNING flags |= THREAD_FLAG_RUNNING
if flags & THREAD_FLAG_WAITING: if flags & THREAD_FLAG_WAITING:
if sleep_count != ~0:
sleep ()
return return
run_thread (this) run_thread (this)
@ -53,41 +64,47 @@ void Thread::unrun ():
return return
flags &= ~THREAD_FLAG_RUNNING flags &= ~THREAD_FLAG_RUNNING
if flags & THREAD_FLAG_WAITING: if flags & THREAD_FLAG_WAITING:
if sleep_count != ~0:
unsleep ()
return return
unrun_thread (this) unrun_thread (this)
void Thread::unwait ():
if !(flags & THREAD_FLAG_WAITING):
return
flags &= ~THREAD_FLAG_WAITING
if sleep_count != ~0:
unsleep ()
if flags & THREAD_FLAG_RUNNING:
run_thread (this)
static void sleep_tick (Thread *thread):
if !thread->sleep_count:
thread->unwait ()
// Time-out: let the thread know with a special message.
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.data[i] = 0
c.cap[i] = NULL
c.copy[i] = false
Thread_arch_receive (thread, ~0, &c)
// Fall through to let sleep be set to ~0, so the next wait will be infinitely long again.
--thread->sleep_count
void Thread::wait (): void Thread::wait ():
if flags & THREAD_FLAG_WAITING: if flags & THREAD_FLAG_WAITING:
return return
if flags & THREAD_FLAG_RUNNING: if flags & THREAD_FLAG_RUNNING:
unrun_thread (this) unrun_thread (this)
flags |= THREAD_FLAG_WAITING flags |= THREAD_FLAG_WAITING
if sleep_count != ~0:
sleep ()
// Try to receive a message from a Receiver immediately. // Try to receive a message from a Receiver immediately.
for Receiver *r = receivers; r; r = r->next_owned: for Receiver *r = receivers; r; r = r->next_owned:
if r->try_deliver (): if r->try_deliver ():
break return
if sleep_count != ~0:
void Thread::unwait (): sleep_tick (this)
if !(flags & THREAD_FLAG_WAITING):
return
flags &= ~THREAD_FLAG_WAITING
if flags & THREAD_FLAG_RUNNING:
run_thread (this)
void timer_interrupt ():
//panic (0x88877744, "Timer interrupt")
Thread *thread, *next
for thread = first_sleeper; thread; thread = next:
next = thread->next
if !--thread->sleep:
if thread->flags & THREAD_FLAG_WAITING:
thread->unwait ()
else:
run_thread (thread)
//#ifndef NDEBUG
//static bool ledstate = false
//dbg_led (false, false, ledstate = !ledstate)
//#endif
void schedule (): void schedule ():
Thread *old = current Thread *old = current
@ -95,3 +112,17 @@ void schedule ():
current = current->schedule_next current = current->schedule_next
if !current: if !current:
current = first_scheduled current = first_scheduled
if !current:
current = &idle
void timer_interrupt ():
//panic (0x88877744, "Timer interrupt")
Thread *thread, *next
for thread = first_sleeper; thread; thread = next:
next = thread->next
sleep_tick (thread)
schedule ()
//#ifndef NDEBUG
//static bool ledstate = false
//dbg_led (false, false, ledstate = !ledstate)
//#endif