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:
parent
eb141d7901
commit
4b47df85e3
@ -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
|
||||||
|
@ -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
|
||||||
|
41
invoke.ccp
41
invoke.ccp
@ -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
19
iris.h
@ -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)
|
||||||
|
@ -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 ()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
@ -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)
|
||||||
|
89
schedule.ccp
89
schedule.ccp
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user