mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-01-30 20:51:05 +02:00
make lcd almost work
This commit is contained in:
parent
eb141d7901
commit
4b47df85e3
@ -179,7 +179,7 @@ Thread *Memory::alloc_thread ():
|
||||
ret->pc = 0
|
||||
ret->sp = 0
|
||||
Thread_arch_init (ret)
|
||||
ret->sleep = 0
|
||||
ret->sleep_count = ~0
|
||||
ret->flags = 0
|
||||
ret->schedule_prev = NULL
|
||||
ret->schedule_next = NULL
|
||||
|
@ -37,97 +37,53 @@ static void set_backlight (bool state):
|
||||
PWM_CTR (0) = 0x3f
|
||||
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 ():
|
||||
gpio_as_pwm ()
|
||||
gpio_as_lcd_master ()
|
||||
|
||||
GPIO_GPDR (2) &= ~PWM_ENABLE
|
||||
PWM_CTR (0) = 0x3f
|
||||
PWM_PER (0) = 300
|
||||
pwm_set_duty (0, 300)
|
||||
pwm_set_full_duty (0)
|
||||
set_backlight (false)
|
||||
|
||||
// initialize things.
|
||||
GPIO_GPIER (2) &= ~(PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA)
|
||||
GPIO_GPDIR (2) |= PWM_ENABLE | LCD_RET | SPEN | SPCK | SPDA
|
||||
udelay (50)
|
||||
GPIO_GPDR (2) &= ~LCD_RET
|
||||
udelay (150000)
|
||||
ddelay (2)
|
||||
GPIO_GPDR (2) |= LCD_RET
|
||||
udelay (10000)
|
||||
lcd_enable ()
|
||||
ddelay (1)
|
||||
|
||||
// For now, support only 16 bpp.
|
||||
// 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_VSYNC = 20
|
||||
LCD_HSYNC = 80
|
||||
LCD_DAV = (20 << 16) | 500
|
||||
LCD_DAH = (80 << 16) | 880
|
||||
LCD_VAT = (880 << 16) | 500
|
||||
//LCD_CFG = MODE_TFT_GEN | PCLK_N | VSYNC_N
|
||||
LCD_VSYNC = vs
|
||||
LCD_HSYNC = hs
|
||||
LCD_DAV = (vs << 16) | (vs + v)
|
||||
LCD_DAH = (hs << 16) | (hs + h)
|
||||
LCD_VAT = ((hs + h) << 16) | (vs + v)
|
||||
#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_MSCR |= 1 << 7
|
||||
cpm_stop_lcd ()
|
||||
|
||||
unsigned pclk = 60 * (800 * 3 + 80) * 500
|
||||
unsigned pllout = cpm_get_pllout ()
|
||||
CPM_CFCR2 = pllout / pclk - 1
|
||||
unsigned v = pllout / (pclk * 4) - 1
|
||||
while v < 0xf && pllout / (v + 1) > 150000000:
|
||||
++v
|
||||
CPM_CFCR = (CPM_CFCR & ~CPM_CFCR_LFR_MASK) | (v << CPM_CFCR_LFR_BIT) | CPM_CFCR_UPE
|
||||
unsigned pixclock = fps * (hs + h) * (vs + v)
|
||||
CPM_CFCR2 = pllout / pixclock - 1
|
||||
|
||||
unsigned val = pllout / (pixclock * 4) - 1
|
||||
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)
|
||||
//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 ():
|
||||
map_gpio ()
|
||||
@ -136,19 +92,20 @@ int main ():
|
||||
map_cpm ()
|
||||
|
||||
reset ()
|
||||
|
||||
while true:
|
||||
set_backlight (false)
|
||||
kdebug (0)
|
||||
register_interrupt (IRQ_LCD)
|
||||
set_backlight (true)
|
||||
kdebug (0)
|
||||
schedule ()
|
||||
|
||||
while true:
|
||||
Message msg
|
||||
if !wait (&msg):
|
||||
continue
|
||||
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:
|
||||
set_backlight (msg.data[0])
|
||||
break
|
||||
|
17
invoke.ccp
17
invoke.ccp
@ -18,6 +18,7 @@
|
||||
|
||||
#include "kernel.hh"
|
||||
|
||||
// From user-provided, thus untrusted, data, find a capability.
|
||||
Capability *Memory::find_capability (unsigned code, bool *copy):
|
||||
if !code:
|
||||
return NULL
|
||||
@ -39,6 +40,7 @@ Capability *Memory::find_capability (unsigned code, bool *copy):
|
||||
return c
|
||||
return NULL
|
||||
|
||||
// Try to deliver a message.
|
||||
bool Receiver::try_deliver ():
|
||||
if !messages || !owner || !owner->is_waiting ():
|
||||
return false
|
||||
@ -61,6 +63,7 @@ bool Receiver::try_deliver ():
|
||||
owner->unwait ()
|
||||
return true
|
||||
|
||||
// Send a message to a receiver; try to deliver it immediately.
|
||||
bool Receiver::send_message (unsigned protected_data, Capability::Context *c):
|
||||
bool tried_direct = false
|
||||
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 ()
|
||||
break
|
||||
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
|
||||
default:
|
||||
value = Thread_arch_info (thread, c->data[1])
|
||||
break
|
||||
if value:
|
||||
*value &= ~c->data[3]
|
||||
*value |= c->data[2] & c->data[3]
|
||||
*value = (*value & ~c->data[3]) | (c->data[2] & c->data[3])
|
||||
reply_num (*value)
|
||||
else:
|
||||
reply_num (0)
|
||||
@ -655,6 +663,7 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
reply_receiver = (Receiver *)protected_data
|
||||
reply_receiver->protected_only = !(target & (1 << CAP_RECEIVER_CALL_ASYNC))
|
||||
Capability *c0 = c->cap[0]
|
||||
if c0:
|
||||
if ((unsigned)c0->target & ~KERNEL_MASK) != 0:
|
||||
Capability r
|
||||
fill_cap (&r, protected_data, reply_receiver->reply_protected_data)
|
||||
@ -662,7 +671,6 @@ static bool kernel_invoke (unsigned target, unsigned protected_data, Capability:
|
||||
c->copy[0] = true
|
||||
c0->target->send_message (c0->protected_data, c)
|
||||
r.invalidate ()
|
||||
return true
|
||||
else:
|
||||
// Kernel call: don't create actual capablities.
|
||||
c->cap[0] = NULL
|
||||
@ -717,4 +725,5 @@ bool Capability::invoke (Capability::Context *c):
|
||||
// This is not a kernel capability: send a message to the receiver.
|
||||
return target->send_message (protected_data, c)
|
||||
// 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)
|
||||
|
19
iris.h
19
iris.h
@ -18,6 +18,13 @@
|
||||
#ifndef __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
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -501,9 +508,17 @@ static unsigned thread_sleep (Capability thread, unsigned value)
|
||||
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)
|
||||
|
@ -33,11 +33,6 @@
|
||||
#define EXTERN extern
|
||||
#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 Page
|
||||
struct Thread
|
||||
@ -73,8 +68,10 @@ struct Thread : public Object <Thread>:
|
||||
unsigned pc, sp
|
||||
Thread_arch arch
|
||||
unsigned flags
|
||||
unsigned sleep
|
||||
unsigned sleep_count
|
||||
Thread *schedule_prev, *schedule_next
|
||||
void sleep ()
|
||||
void unsleep ()
|
||||
void run ()
|
||||
void unrun ()
|
||||
void wait ()
|
||||
|
@ -111,9 +111,6 @@ start_idle: // 280
|
||||
// Wait for the next interrupt, then the first thread will be scheduled.
|
||||
// It is impractical to try to call schedule, because for that the
|
||||
// idle task would need to own capabilities.
|
||||
move $v0, $zero
|
||||
syscall
|
||||
nop
|
||||
1: wait
|
||||
b 1b
|
||||
nop
|
||||
@ -221,7 +218,8 @@ save_regs:
|
||||
#ifndef NDEBUG
|
||||
// Allow interrupts to set EPC and friends.
|
||||
mfc0 $k0, $CP0_STATUS
|
||||
andi $k0, $k0, 0xff00
|
||||
li $k1, 0x1000ff00
|
||||
and $k0, $k0, $k1
|
||||
mtc0 $k0, $CP0_STATUS
|
||||
#endif
|
||||
|
||||
|
@ -257,12 +257,14 @@ void init ():
|
||||
GPIO_GPDIR (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.
|
||||
unsigned latch = (JZ_EXTAL + (HZ>>1)) / HZ
|
||||
// Start the operating system timer, and set it to give an interrupt immediately.
|
||||
// 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_set_mode (0, OST_TCSR_UIE | OST_TCSR_CKS_EXTAL)
|
||||
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_enable_channel (0)
|
||||
intc_unmask_irq (IRQ_OST0)
|
||||
|
@ -19,11 +19,40 @@
|
||||
#define ARCH
|
||||
#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
|
||||
/// when k0 or k1 is not 0, or when an error occurs.
|
||||
/// Otherwise, the ultra-fast code in entry.S is used.
|
||||
Thread *tlb_refill ():
|
||||
//panic (0x88776655, "TLB refill")
|
||||
Thread *old_current = current
|
||||
if !directory:
|
||||
panic (0x44449999, "No directory")
|
||||
unsigned EntryHi
|
||||
@ -41,11 +70,13 @@ Thread *tlb_refill ():
|
||||
cp0_set (CP0_ENTRY_LO0, t[idx])
|
||||
cp0_set (CP0_ENTRY_LO1, t[idx + 1])
|
||||
__asm__ volatile ("tlbwr")
|
||||
handle_exit (old_current)
|
||||
return current
|
||||
|
||||
/// An interrupt which is not an exception has occurred.
|
||||
Thread *interrupt ():
|
||||
//panic (0x88877722, "Interrupt")
|
||||
Thread *old_current = current
|
||||
//dbg_send (INTC_IPR)
|
||||
unsigned ipr = INTC_IPR
|
||||
for unsigned i = 0; i < 32; ++i:
|
||||
@ -68,6 +99,7 @@ Thread *interrupt ():
|
||||
ost_clear_uf (0)
|
||||
intc_ack_irq (IRQ_OST0)
|
||||
timer_interrupt ()
|
||||
handle_exit (old_current)
|
||||
return current
|
||||
|
||||
void flush_tlb (unsigned asid):
|
||||
@ -87,10 +119,9 @@ static void arch_invoke ():
|
||||
Thread *caller = current
|
||||
target = caller->address_space->find_capability (caller->arch.v0, &wait)
|
||||
if !target:
|
||||
// TODO: there must be no action here. This is just because the rest doesn't work yet.
|
||||
dbg_send (3, 2)
|
||||
// There must be no action here.
|
||||
//dbg_send (3, 2)
|
||||
//dbg_send (caller->arch.v0)
|
||||
schedule ()
|
||||
// Calling an invalid capability always fails.
|
||||
caller->arch.v0 = 0
|
||||
else:
|
||||
@ -108,35 +139,10 @@ static void arch_invoke ():
|
||||
caller->arch.v0 = target->invoke (&c) ? 1 : 0
|
||||
if caller != current && caller != &idle && (caller->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING:
|
||||
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.
|
||||
Thread *exception ():
|
||||
Thread *old_current = current
|
||||
unsigned cause
|
||||
cp0_get (CP0_CAUSE, cause)
|
||||
switch (cause >> 2) & 0x1f:
|
||||
@ -220,9 +226,12 @@ Thread *exception ():
|
||||
panic (0xf5223344, "Reserved exception code")
|
||||
default:
|
||||
panic (0xf6223344, "Impossible exception code")
|
||||
handle_exit (old_current)
|
||||
return current
|
||||
|
||||
/// There's a cache error. Big trouble. Probably not worth trying to recover.
|
||||
Thread *cache_error ():
|
||||
panic (0x33333333, "cache error")
|
||||
Thread *old_current = current
|
||||
handle_exit (old_current)
|
||||
return current
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
// Main clock, for cpu, serial port, and with divisors for most other hardware
|
||||
#define JZ_EXTAL 3686400
|
||||
//#define JZ_EXTAL 3072000
|
||||
// RTC clock
|
||||
#define RTC_CLOCK 32768
|
||||
|
||||
@ -2311,8 +2312,9 @@ static __inline__ void udelay (unsigned us):
|
||||
GPIO_GPDR (0) = GPIO_GPDR (0)
|
||||
|
||||
#ifndef __KERNEL
|
||||
static __inline__ void mdelay (unsigned ms):
|
||||
my_sleep ((ms + 99) / 100)
|
||||
static __inline__ void ddelay (unsigned ds):
|
||||
Message m
|
||||
my_sleep (ds, &m)
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -109,6 +109,6 @@ void dbg_send (unsigned code, unsigned bits):
|
||||
dbg_led (false, false, false)
|
||||
dbg_sleep (200)
|
||||
dbg_led (true, true, false)
|
||||
dbg_sleep (500)
|
||||
dbg_sleep (50)
|
||||
dbg_led (false, false, false)
|
||||
dbg_sleep (500)
|
||||
dbg_sleep (50)
|
||||
|
87
schedule.ccp
87
schedule.ccp
@ -33,18 +33,29 @@ static void unrun_thread (Thread *thread):
|
||||
first_scheduled = thread->schedule_next
|
||||
if thread->schedule_next:
|
||||
thread->schedule_next->schedule_prev = thread->schedule_prev
|
||||
if thread->sleep:
|
||||
thread->schedule_next = first_sleeper
|
||||
thread->schedule_prev = NULL
|
||||
if thread->schedule_next:
|
||||
thread->schedule_next->schedule_prev = thread
|
||||
first_sleeper = thread
|
||||
|
||||
void Thread::sleep ():
|
||||
schedule_next = first_sleeper
|
||||
if schedule_next:
|
||||
schedule_next->schedule_prev = this
|
||||
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 ():
|
||||
if flags & THREAD_FLAG_RUNNING:
|
||||
return
|
||||
flags |= THREAD_FLAG_RUNNING
|
||||
if flags & THREAD_FLAG_WAITING:
|
||||
if sleep_count != ~0:
|
||||
sleep ()
|
||||
return
|
||||
run_thread (this)
|
||||
|
||||
@ -53,41 +64,47 @@ void Thread::unrun ():
|
||||
return
|
||||
flags &= ~THREAD_FLAG_RUNNING
|
||||
if flags & THREAD_FLAG_WAITING:
|
||||
if sleep_count != ~0:
|
||||
unsleep ()
|
||||
return
|
||||
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 ():
|
||||
if flags & THREAD_FLAG_WAITING:
|
||||
return
|
||||
if flags & THREAD_FLAG_RUNNING:
|
||||
unrun_thread (this)
|
||||
flags |= THREAD_FLAG_WAITING
|
||||
if sleep_count != ~0:
|
||||
sleep ()
|
||||
// Try to receive a message from a Receiver immediately.
|
||||
for Receiver *r = receivers; r; r = r->next_owned:
|
||||
if r->try_deliver ():
|
||||
break
|
||||
|
||||
void Thread::unwait ():
|
||||
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
|
||||
if sleep_count != ~0:
|
||||
sleep_tick (this)
|
||||
|
||||
void schedule ():
|
||||
Thread *old = current
|
||||
@ -95,3 +112,17 @@ void schedule ():
|
||||
current = current->schedule_next
|
||||
if !current:
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user