mirror of
https://github.com/cccriscv/mini-riscv-os.git
synced 2025-12-05 15:15:31 +00:00
getc() supported!
This commit is contained in:
40
07-ExterInterrupt/Makefile
Normal file
40
07-ExterInterrupt/Makefile
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
CC = riscv64-unknown-elf-gcc
|
||||||
|
CFLAGS = -nostdlib -fno-builtin -mcmodel=medany -march=rv32ima -mabi=ilp32
|
||||||
|
GDB = riscv64-unknown-elf-gdb
|
||||||
|
|
||||||
|
OBJ = \
|
||||||
|
start.s \
|
||||||
|
sys.s \
|
||||||
|
lib.c \
|
||||||
|
timer.c \
|
||||||
|
task.c \
|
||||||
|
os.c \
|
||||||
|
user.c \
|
||||||
|
trap.c \
|
||||||
|
lock.c \
|
||||||
|
plic.c
|
||||||
|
|
||||||
|
QEMU = qemu-system-riscv32
|
||||||
|
QFLAGS = -nographic -smp 4 -machine virt -bios none
|
||||||
|
|
||||||
|
OBJDUMP = riscv64-unknown-elf-objdump
|
||||||
|
|
||||||
|
all: os.elf
|
||||||
|
|
||||||
|
os.elf: $(OBJ)
|
||||||
|
$(CC) $(CFLAGS) -g -Wall -T os.ld -o os.elf $^
|
||||||
|
|
||||||
|
qemu: $(TARGET)
|
||||||
|
@qemu-system-riscv32 -M ? | grep virt >/dev/null || exit
|
||||||
|
@echo "Press Ctrl-A and then X to exit QEMU"
|
||||||
|
$(QEMU) $(QFLAGS) -kernel os.elf
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.elf
|
||||||
|
|
||||||
|
.PHONY : debug
|
||||||
|
debug: all
|
||||||
|
@echo "Press Ctrl-C and then input 'quit' to exit GDB and QEMU"
|
||||||
|
@echo "-------------------------------------------------------"
|
||||||
|
@${QEMU} ${QFLAGS} -kernel os.elf -s -S &
|
||||||
|
@${GDB} os.elf -q -x ./gdbinit
|
||||||
54
07-ExterInterrupt/README.md
Normal file
54
07-ExterInterrupt/README.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# 07-ExternInterrupt
|
||||||
|
|
||||||
|
## Build & Run
|
||||||
|
|
||||||
|
```sh
|
||||||
|
IAN@DESKTOP-9AEMEPL MINGW64 ~/Desktop/mini-riscv-os/07-ExterInterrupt (feat/getchar)
|
||||||
|
$ make
|
||||||
|
riscv64-unknown-elf-gcc -nostdlib -fno-builtin -mcmodel=medany -march=rv32ima -mabi=ilp32 -g -Wall -T os.ld -o os.elf start.s sys.s lib.c timer.c task.c os.c user.c trap.c lock.c plic.c
|
||||||
|
|
||||||
|
IAN@DESKTOP-9AEMEPL MINGW64 ~/Desktop/mini-riscv-os/07-ExterInterrupt (feat/getchar)
|
||||||
|
$ make qemu
|
||||||
|
Press Ctrl-A and then X to exit QEMU
|
||||||
|
qemu-system-riscv32 -nographic -smp 4 -machine virt -bios none -kernel os.elf
|
||||||
|
OS start
|
||||||
|
OS: Activate next task
|
||||||
|
Hi!
|
||||||
|
timer interruption!
|
||||||
|
timer_handler: 1
|
||||||
|
OS: Back to OS
|
||||||
|
|
||||||
|
OS: Activate next task
|
||||||
|
QEMU: Terminated
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debug mode
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make debug
|
||||||
|
riscv64-unknown-elf-gcc -nostdlib -fno-builtin -mcmodel=medany -march=rv32ima -mabi=ilp32 -g -Wall -T os.ld -o os.elf start.s sys.s lib.c timer.c task.c os.c user.c trap.c lock.c
|
||||||
|
Press Ctrl-C and then input 'quit' to exit GDB and QEMU
|
||||||
|
-------------------------------------------------------
|
||||||
|
Reading symbols from os.elf...
|
||||||
|
Breakpoint 1 at 0x80000000: file start.s, line 7.
|
||||||
|
0x00001000 in ?? ()
|
||||||
|
=> 0x00001000: 97 02 00 00 auipc t0,0x0
|
||||||
|
|
||||||
|
Thread 1 hit Breakpoint 1, _start () at start.s:7
|
||||||
|
7 csrr t0, mhartid # read current hart id
|
||||||
|
=> 0x80000000 <_start+0>: f3 22 40 f1 csrr t0,mhartid
|
||||||
|
(gdb)
|
||||||
|
```
|
||||||
|
|
||||||
|
### set the breakpoint
|
||||||
|
|
||||||
|
You can set the breakpoint in any c file:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
(gdb) b trap.c:27
|
||||||
|
Breakpoint 2 at 0x80008f78: file trap.c, line 27.
|
||||||
|
(gdb)
|
||||||
|
```
|
||||||
|
|
||||||
|
As the example above, when process running on trap.c, line 27 (Timer Interrupt).
|
||||||
|
The process will be suspended automatically until you press the key `c` (continue) or `s` (step).
|
||||||
4
07-ExterInterrupt/gdbinit
Normal file
4
07-ExterInterrupt/gdbinit
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
set disassemble-next-line on
|
||||||
|
b _start
|
||||||
|
target remote : 1234
|
||||||
|
c
|
||||||
225
07-ExterInterrupt/lib.c
Normal file
225
07-ExterInterrupt/lib.c
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
#define LSR_RX_READY (1 << 0)
|
||||||
|
#define LSR_TX_IDLE (1 << 5)
|
||||||
|
|
||||||
|
void uart_init()
|
||||||
|
{
|
||||||
|
/* disable interrupts */
|
||||||
|
UART_REGW(UART_IER, 0x00);
|
||||||
|
|
||||||
|
/* Baud rate setting */
|
||||||
|
uint8_t lcr = UART_REGR(UART_LCR);
|
||||||
|
UART_REGW(UART_LCR, lcr | (1 << 7));
|
||||||
|
UART_REGW(UART_DLL, 0x03);
|
||||||
|
UART_REGW(UART_DLM, 0x00);
|
||||||
|
|
||||||
|
lcr = 0;
|
||||||
|
UART_REGW(UART_LCR, lcr | (3 << 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int lib_getc(void)
|
||||||
|
{
|
||||||
|
if (*UART_LSR & LSR_RX_READY)
|
||||||
|
{
|
||||||
|
return *UART_RHR == '\r' ? '\n' : *UART_RHR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lib_isr(void)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int c = lib_getc();
|
||||||
|
if (c == -1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lib_putc((char)c);
|
||||||
|
lib_putc('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lib_delay(volatile int count)
|
||||||
|
{
|
||||||
|
count *= 50000;
|
||||||
|
while (count--)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lib_putc(char ch)
|
||||||
|
{
|
||||||
|
while ((*UART_LSR & UART_LSR_EMPTY_MASK) == 0)
|
||||||
|
;
|
||||||
|
return *UART_THR = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lib_puts(char *s)
|
||||||
|
{
|
||||||
|
while (*s)
|
||||||
|
lib_putc(*s++);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lib_vsnprintf(char *out, size_t n, const char *s, va_list vl)
|
||||||
|
{
|
||||||
|
int format = 0;
|
||||||
|
int longarg = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
for (; *s; s++)
|
||||||
|
{
|
||||||
|
if (format)
|
||||||
|
{
|
||||||
|
switch (*s)
|
||||||
|
{
|
||||||
|
case 'l':
|
||||||
|
{
|
||||||
|
longarg = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'p':
|
||||||
|
{
|
||||||
|
longarg = 1;
|
||||||
|
if (out && pos < n)
|
||||||
|
{
|
||||||
|
out[pos] = '0';
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
if (out && pos < n)
|
||||||
|
{
|
||||||
|
out[pos] = 'x';
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
case 'x':
|
||||||
|
{
|
||||||
|
long num = longarg ? va_arg(vl, long) : va_arg(vl, int);
|
||||||
|
int hexdigits = 2 * (longarg ? sizeof(long) : sizeof(int)) - 1;
|
||||||
|
for (int i = hexdigits; i >= 0; i--)
|
||||||
|
{
|
||||||
|
int d = (num >> (4 * i)) & 0xF;
|
||||||
|
if (out && pos < n)
|
||||||
|
{
|
||||||
|
out[pos] = (d < 10 ? '0' + d : 'a' + d - 10);
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
longarg = 0;
|
||||||
|
format = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
{
|
||||||
|
long num = longarg ? va_arg(vl, long) : va_arg(vl, int);
|
||||||
|
if (num < 0)
|
||||||
|
{
|
||||||
|
num = -num;
|
||||||
|
if (out && pos < n)
|
||||||
|
{
|
||||||
|
out[pos] = '-';
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
long digits = 1;
|
||||||
|
for (long nn = num; nn /= 10; digits++)
|
||||||
|
;
|
||||||
|
for (int i = digits - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (out && pos + i < n)
|
||||||
|
{
|
||||||
|
out[pos + i] = '0' + (num % 10);
|
||||||
|
}
|
||||||
|
num /= 10;
|
||||||
|
}
|
||||||
|
pos += digits;
|
||||||
|
longarg = 0;
|
||||||
|
format = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
const char *s2 = va_arg(vl, const char *);
|
||||||
|
while (*s2)
|
||||||
|
{
|
||||||
|
if (out && pos < n)
|
||||||
|
{
|
||||||
|
out[pos] = *s2;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
longarg = 0;
|
||||||
|
format = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'c':
|
||||||
|
{
|
||||||
|
if (out && pos < n)
|
||||||
|
{
|
||||||
|
out[pos] = (char)va_arg(vl, int);
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
longarg = 0;
|
||||||
|
format = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*s == '%')
|
||||||
|
{
|
||||||
|
format = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (out && pos < n)
|
||||||
|
{
|
||||||
|
out[pos] = *s;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (out && pos < n)
|
||||||
|
{
|
||||||
|
out[pos] = 0;
|
||||||
|
}
|
||||||
|
else if (out && n)
|
||||||
|
{
|
||||||
|
out[n - 1] = 0;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char out_buf[1000]; // buffer for lib_vprintf()
|
||||||
|
|
||||||
|
int lib_vprintf(const char *s, va_list vl)
|
||||||
|
{
|
||||||
|
int res = lib_vsnprintf(NULL, -1, s, vl);
|
||||||
|
if (res + 1 >= sizeof(out_buf))
|
||||||
|
{
|
||||||
|
lib_puts("error: lib_vprintf() output string size overflow\n");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lib_vsnprintf(out_buf, res + 1, s, vl);
|
||||||
|
lib_puts(out_buf);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lib_printf(const char *s, ...)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, s);
|
||||||
|
res = lib_vprintf(s, vl);
|
||||||
|
va_end(vl);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
26
07-ExterInterrupt/lib.h
Normal file
26
07-ExterInterrupt/lib.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef __LIB_H__
|
||||||
|
#define __LIB_H__
|
||||||
|
|
||||||
|
#include "riscv.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define lib_error(...) \
|
||||||
|
{ \
|
||||||
|
lib_printf(__VA_ARGS__); \
|
||||||
|
while (1) \
|
||||||
|
{ \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void uart_init();
|
||||||
|
extern int lib_getc(void);
|
||||||
|
extern void lib_delay(volatile int count);
|
||||||
|
extern int lib_putc(char ch);
|
||||||
|
extern void lib_puts(char *s);
|
||||||
|
extern int lib_printf(const char *s, ...);
|
||||||
|
extern int lib_vprintf(const char *s, va_list vl);
|
||||||
|
extern int lib_vsnprintf(char *out, size_t n, const char *s, va_list vl);
|
||||||
|
|
||||||
|
#endif
|
||||||
32
07-ExterInterrupt/lock.c
Normal file
32
07-ExterInterrupt/lock.c
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
void lock_init(lock_t *lock)
|
||||||
|
{
|
||||||
|
lock->locked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock_acquire(lock_t *lock)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (!atomic_swap(lock))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock_free(lock_t *lock)
|
||||||
|
{
|
||||||
|
lock->locked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void basic_lock()
|
||||||
|
{
|
||||||
|
w_mstatus(r_mstatus() & ~MSTATUS_MIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void basic_unlock()
|
||||||
|
{
|
||||||
|
w_mstatus(r_mstatus() | MSTATUS_MIE);
|
||||||
|
}
|
||||||
34
07-ExterInterrupt/os.c
Normal file
34
07-ExterInterrupt/os.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
extern void trap_init(void);
|
||||||
|
|
||||||
|
void os_kernel()
|
||||||
|
{
|
||||||
|
task_os();
|
||||||
|
}
|
||||||
|
|
||||||
|
void os_start()
|
||||||
|
{
|
||||||
|
lib_puts("OS start\n");
|
||||||
|
uart_init();
|
||||||
|
user_init();
|
||||||
|
trap_init();
|
||||||
|
plic_init();
|
||||||
|
timer_init(); // start timer interrupt ...
|
||||||
|
}
|
||||||
|
|
||||||
|
int os_main(void)
|
||||||
|
{
|
||||||
|
os_start();
|
||||||
|
|
||||||
|
int current_task = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
lib_puts("OS: Activate next task\n");
|
||||||
|
task_go(current_task);
|
||||||
|
lib_puts("OS: Back to OS\n");
|
||||||
|
current_task = (current_task + 1) % taskTop; // Round Robin Scheduling
|
||||||
|
lib_puts("\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
35
07-ExterInterrupt/os.h
Normal file
35
07-ExterInterrupt/os.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef __OS_H__
|
||||||
|
#define __OS_H__
|
||||||
|
|
||||||
|
#include "riscv.h"
|
||||||
|
#include "lib.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
extern void user_init();
|
||||||
|
extern void os_kernel();
|
||||||
|
extern int os_main(void);
|
||||||
|
|
||||||
|
// PLIC
|
||||||
|
extern void plic_init();
|
||||||
|
extern int plic_claim();
|
||||||
|
extern void plic_complete(int);
|
||||||
|
|
||||||
|
// lock
|
||||||
|
extern void basic_lock();
|
||||||
|
extern void basic_unlock();
|
||||||
|
|
||||||
|
typedef struct lock
|
||||||
|
{
|
||||||
|
volatile int locked;
|
||||||
|
} lock_t;
|
||||||
|
|
||||||
|
extern int atomic_swap(lock_t *);
|
||||||
|
|
||||||
|
extern void lock_init(lock_t *lock);
|
||||||
|
|
||||||
|
extern void lock_acquire(lock_t *lock);
|
||||||
|
|
||||||
|
extern void lock_free(lock_t *lock);
|
||||||
|
|
||||||
|
#endif
|
||||||
46
07-ExterInterrupt/os.ld
Normal file
46
07-ExterInterrupt/os.ld
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
OUTPUT_ARCH( "riscv" )
|
||||||
|
|
||||||
|
ENTRY( _start )
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M
|
||||||
|
}
|
||||||
|
|
||||||
|
PHDRS
|
||||||
|
{
|
||||||
|
text PT_LOAD;
|
||||||
|
data PT_LOAD;
|
||||||
|
bss PT_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text : {
|
||||||
|
PROVIDE(_text_start = .);
|
||||||
|
*(.text.init) *(.text .text.*)
|
||||||
|
PROVIDE(_text_end = .);
|
||||||
|
} >ram AT>ram :text
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
PROVIDE(_rodata_start = .);
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
PROVIDE(_rodata_end = .);
|
||||||
|
} >ram AT>ram :text
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
. = ALIGN(4096);
|
||||||
|
PROVIDE(_data_start = .);
|
||||||
|
*(.sdata .sdata.*) *(.data .data.*)
|
||||||
|
PROVIDE(_data_end = .);
|
||||||
|
} >ram AT>ram :data
|
||||||
|
|
||||||
|
.bss :{
|
||||||
|
PROVIDE(_bss_start = .);
|
||||||
|
*(.sbss .sbss.*) *(.bss .bss.*)
|
||||||
|
PROVIDE(_bss_end = .);
|
||||||
|
} >ram AT>ram :bss
|
||||||
|
|
||||||
|
PROVIDE(_memory_start = ORIGIN(ram));
|
||||||
|
PROVIDE(_memory_end = ORIGIN(ram) + LENGTH(ram));
|
||||||
|
}
|
||||||
33
07-ExterInterrupt/plic.c
Normal file
33
07-ExterInterrupt/plic.c
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
void plic_init()
|
||||||
|
{
|
||||||
|
int hart = r_mhartid();
|
||||||
|
|
||||||
|
// QEMU Virt machine support 7 priority (1 - 7),
|
||||||
|
// The "0" is reserved, and the lowest priority is "1".
|
||||||
|
*(uint32_t *)PLIC_PRIORITY(UART0_IRQ) = 1;
|
||||||
|
|
||||||
|
/* Enable UART0 */
|
||||||
|
*(uint32_t *)PLIC_MENABLE(hart) = (1 << UART0_IRQ);
|
||||||
|
|
||||||
|
/* Set priority threshold for UART0. */
|
||||||
|
|
||||||
|
*(uint32_t *)PLIC_MTHRESHOLD(hart) = 0;
|
||||||
|
|
||||||
|
/* enable machine-mode external interrupts. */
|
||||||
|
w_mie(r_mie() | MIE_MEIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int plic_claim()
|
||||||
|
{
|
||||||
|
int hart = r_mhartid();
|
||||||
|
int irq = *(uint32_t *)PLIC_MCLAIM(hart);
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plic_complete(int irq)
|
||||||
|
{
|
||||||
|
int hart = r_mhartid();
|
||||||
|
*(uint32_t *)PLIC_MCOMPLETE(hart) = irq;
|
||||||
|
}
|
||||||
154
07-ExterInterrupt/riscv.h
Normal file
154
07-ExterInterrupt/riscv.h
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
#ifndef __RISCV_H__
|
||||||
|
#define __RISCV_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define reg_t uint32_t // RISCV32: register is 32bits
|
||||||
|
// define reg_t as uint64_t // RISCV64: register is 64bits
|
||||||
|
|
||||||
|
// ref: https://github.com/qemu/qemu/blob/master/include/hw/riscv/virt.h
|
||||||
|
// Intro: https://github.com/ianchen0119/AwesomeCS/wiki/2-5-RISC-V::%E4%B8%AD%E6%96%B7%E8%88%87%E7%95%B0%E5%B8%B8%E8%99%95%E7%90%86----PLIC-%E4%BB%8B%E7%B4%B9
|
||||||
|
#define PLIC_BASE 0x0c000000L
|
||||||
|
#define PLIC_PRIORITY(id) (PLIC_BASE + (id)*4)
|
||||||
|
#define PLIC_PENDING(id) (PLIC_BASE + 0x1000 + ((id) / 32))
|
||||||
|
#define PLIC_MENABLE(hart) (PLIC_BASE + 0x2000 + (hart)*0x80)
|
||||||
|
#define PLIC_MTHRESHOLD(hart) (PLIC_BASE + 0x200000 + (hart)*0x1000)
|
||||||
|
#define PLIC_MCLAIM(hart) (PLIC_BASE + 0x200004 + (hart)*0x1000)
|
||||||
|
#define PLIC_MCOMPLETE(hart) (PLIC_BASE + 0x200004 + (hart)*0x1000)
|
||||||
|
|
||||||
|
// ref: https://www.activexperts.com/serial-port-component/tutorials/uart/
|
||||||
|
#define UART 0x10000000
|
||||||
|
#define UART_THR (uint8_t *)(UART + 0x00) // THR:transmitter holding register
|
||||||
|
#define UART_RHR (uint8_t *)(UART + 0x00) // RHR:Receive holding register
|
||||||
|
#define UART_DLL (uint8_t *)(UART + 0x00) // LSB of Divisor Latch (write mode)
|
||||||
|
#define UART_DLM (uint8_t *)(UART + 0x01) // MSB of Divisor Latch (write mode)
|
||||||
|
#define UART_IER (uint8_t *)(UART + 0x01) // Interrupt Enable Register
|
||||||
|
#define UART_LCR (uint8_t *)(UART + 0x03) // Line Control Register
|
||||||
|
#define UART_LSR (uint8_t *)(UART + 0x05) // LSR:line status register
|
||||||
|
#define UART_LSR_EMPTY_MASK 0x40 // LSR Bit 6: Transmitter empty; both the THR and LSR are empty
|
||||||
|
|
||||||
|
#define UART_REG(reg) ((volatile uint8_t *)(UART + reg))
|
||||||
|
#define UART_REGR(reg) (*(UART_REG(reg)))
|
||||||
|
#define UART_REGW(reg, v) (*(UART_REG(reg)) = (v))
|
||||||
|
|
||||||
|
// ref: https://github.com/qemu/qemu/blob/master/include/hw/riscv/virt.h
|
||||||
|
#define UART0_IRQ 10
|
||||||
|
#define VIRTIO_IRQ 1
|
||||||
|
|
||||||
|
// Saved registers for kernel context switches.
|
||||||
|
struct context
|
||||||
|
{
|
||||||
|
reg_t ra;
|
||||||
|
reg_t sp;
|
||||||
|
|
||||||
|
// callee-saved
|
||||||
|
reg_t s0;
|
||||||
|
reg_t s1;
|
||||||
|
reg_t s2;
|
||||||
|
reg_t s3;
|
||||||
|
reg_t s4;
|
||||||
|
reg_t s5;
|
||||||
|
reg_t s6;
|
||||||
|
reg_t s7;
|
||||||
|
reg_t s8;
|
||||||
|
reg_t s9;
|
||||||
|
reg_t s10;
|
||||||
|
reg_t s11;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ref: https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/riscv.h
|
||||||
|
//
|
||||||
|
// local interrupt controller, which contains the timer.
|
||||||
|
// ================== Timer Interrput ====================
|
||||||
|
|
||||||
|
#define NCPU 8 // maximum number of CPUs
|
||||||
|
#define CLINT 0x2000000
|
||||||
|
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 4 * (hartid))
|
||||||
|
#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot.
|
||||||
|
|
||||||
|
// which hart (core) is this?
|
||||||
|
static inline reg_t r_mhartid()
|
||||||
|
{
|
||||||
|
reg_t x;
|
||||||
|
asm volatile("csrr %0, mhartid"
|
||||||
|
: "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Status Register, mstatus
|
||||||
|
#define MSTATUS_MPP_MASK (3 << 11) // previous mode.
|
||||||
|
#define MSTATUS_MPP_M (3 << 11)
|
||||||
|
#define MSTATUS_MPP_S (1 << 11)
|
||||||
|
#define MSTATUS_MPP_U (0 << 11)
|
||||||
|
#define MSTATUS_MIE (1 << 3) // machine-mode interrupt enable.
|
||||||
|
|
||||||
|
static inline reg_t r_mstatus()
|
||||||
|
{
|
||||||
|
reg_t x;
|
||||||
|
asm volatile("csrr %0, mstatus"
|
||||||
|
: "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void w_mstatus(reg_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mstatus, %0"
|
||||||
|
:
|
||||||
|
: "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// machine exception program counter, holds the
|
||||||
|
// instruction address to which a return from
|
||||||
|
// exception will go.
|
||||||
|
static inline void w_mepc(reg_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mepc, %0"
|
||||||
|
:
|
||||||
|
: "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline reg_t r_mepc()
|
||||||
|
{
|
||||||
|
reg_t x;
|
||||||
|
asm volatile("csrr %0, mepc"
|
||||||
|
: "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine Scratch register, for early trap handler
|
||||||
|
static inline void w_mscratch(reg_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mscratch, %0"
|
||||||
|
:
|
||||||
|
: "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine-mode interrupt vector
|
||||||
|
static inline void w_mtvec(reg_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mtvec, %0"
|
||||||
|
:
|
||||||
|
: "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Machine-mode Interrupt Enable
|
||||||
|
#define MIE_MEIE (1 << 11) // external
|
||||||
|
#define MIE_MTIE (1 << 7) // timer
|
||||||
|
#define MIE_MSIE (1 << 3) // software
|
||||||
|
|
||||||
|
static inline reg_t r_mie()
|
||||||
|
{
|
||||||
|
reg_t x;
|
||||||
|
asm volatile("csrr %0, mie"
|
||||||
|
: "=r"(x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void w_mie(reg_t x)
|
||||||
|
{
|
||||||
|
asm volatile("csrw mie, %0"
|
||||||
|
:
|
||||||
|
: "r"(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
26
07-ExterInterrupt/start.s
Normal file
26
07-ExterInterrupt/start.s
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
.equ STACK_SIZE, 8192
|
||||||
|
|
||||||
|
.global _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
# setup stacks per hart
|
||||||
|
csrr t0, mhartid # read current hart id
|
||||||
|
slli t0, t0, 10 # shift left the hart id by 1024
|
||||||
|
la sp, stacks + STACK_SIZE # set the initial stack pointer
|
||||||
|
# to the end of the stack space
|
||||||
|
add sp, sp, t0 # move the current hart stack pointer
|
||||||
|
# to its place in the stack space
|
||||||
|
|
||||||
|
# park harts with id != 0
|
||||||
|
csrr a0, mhartid # read current hart id
|
||||||
|
bnez a0, park # if we're not on the hart 0
|
||||||
|
# we park the hart
|
||||||
|
|
||||||
|
j os_main # hart 0 jump to c
|
||||||
|
|
||||||
|
park:
|
||||||
|
wfi
|
||||||
|
j park
|
||||||
|
|
||||||
|
stacks:
|
||||||
|
.skip STACK_SIZE * 4 # allocate space for the harts stacks
|
||||||
8
07-ExterInterrupt/sys.h
Normal file
8
07-ExterInterrupt/sys.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef __SYS_H__
|
||||||
|
#define __SYS_H__
|
||||||
|
|
||||||
|
#include "riscv.h"
|
||||||
|
extern void sys_timer();
|
||||||
|
extern void sys_switch(struct context *ctx_old, struct context *ctx_new);
|
||||||
|
|
||||||
|
#endif
|
||||||
152
07-ExterInterrupt/sys.s
Normal file
152
07-ExterInterrupt/sys.s
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# This Code derived from xv6-riscv (64bit)
|
||||||
|
# -- https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/swtch.S
|
||||||
|
|
||||||
|
# ============ MACRO ==================
|
||||||
|
.macro ctx_save base
|
||||||
|
sw ra, 0(\base)
|
||||||
|
sw sp, 4(\base)
|
||||||
|
sw s0, 8(\base)
|
||||||
|
sw s1, 12(\base)
|
||||||
|
sw s2, 16(\base)
|
||||||
|
sw s3, 20(\base)
|
||||||
|
sw s4, 24(\base)
|
||||||
|
sw s5, 28(\base)
|
||||||
|
sw s6, 32(\base)
|
||||||
|
sw s7, 36(\base)
|
||||||
|
sw s8, 40(\base)
|
||||||
|
sw s9, 44(\base)
|
||||||
|
sw s10, 48(\base)
|
||||||
|
sw s11, 52(\base)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro ctx_load base
|
||||||
|
lw ra, 0(\base)
|
||||||
|
lw sp, 4(\base)
|
||||||
|
lw s0, 8(\base)
|
||||||
|
lw s1, 12(\base)
|
||||||
|
lw s2, 16(\base)
|
||||||
|
lw s3, 20(\base)
|
||||||
|
lw s4, 24(\base)
|
||||||
|
lw s5, 28(\base)
|
||||||
|
lw s6, 32(\base)
|
||||||
|
lw s7, 36(\base)
|
||||||
|
lw s8, 40(\base)
|
||||||
|
lw s9, 44(\base)
|
||||||
|
lw s10, 48(\base)
|
||||||
|
lw s11, 52(\base)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro reg_save base
|
||||||
|
# save the registers.
|
||||||
|
sw ra, 0(\base)
|
||||||
|
sw sp, 4(\base)
|
||||||
|
sw gp, 8(\base)
|
||||||
|
sw tp, 12(\base)
|
||||||
|
sw t0, 16(\base)
|
||||||
|
sw t1, 20(\base)
|
||||||
|
sw t2, 24(\base)
|
||||||
|
sw s0, 28(\base)
|
||||||
|
sw s1, 32(\base)
|
||||||
|
sw a0, 36(\base)
|
||||||
|
sw a1, 40(\base)
|
||||||
|
sw a2, 44(\base)
|
||||||
|
sw a3, 48(\base)
|
||||||
|
sw a4, 52(\base)
|
||||||
|
sw a5, 56(\base)
|
||||||
|
sw a6, 60(\base)
|
||||||
|
sw a7, 64(\base)
|
||||||
|
sw s2, 68(\base)
|
||||||
|
sw s3, 72(\base)
|
||||||
|
sw s4, 76(\base)
|
||||||
|
sw s5, 80(\base)
|
||||||
|
sw s6, 84(\base)
|
||||||
|
sw s7, 88(\base)
|
||||||
|
sw s8, 92(\base)
|
||||||
|
sw s9, 96(\base)
|
||||||
|
sw s10, 100(\base)
|
||||||
|
sw s11, 104(\base)
|
||||||
|
sw t3, 108(\base)
|
||||||
|
sw t4, 112(\base)
|
||||||
|
sw t5, 116(\base)
|
||||||
|
sw t6, 120(\base)
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro reg_load base
|
||||||
|
# restore registers.
|
||||||
|
lw ra, 0(\base)
|
||||||
|
lw sp, 4(\base)
|
||||||
|
lw gp, 8(\base)
|
||||||
|
# not this, in case we moved CPUs: lw tp, 12(\base)
|
||||||
|
lw t0, 16(\base)
|
||||||
|
lw t1, 20(\base)
|
||||||
|
lw t2, 24(\base)
|
||||||
|
lw s0, 28(\base)
|
||||||
|
lw s1, 32(\base)
|
||||||
|
lw a0, 36(\base)
|
||||||
|
lw a1, 40(\base)
|
||||||
|
lw a2, 44(\base)
|
||||||
|
lw a3, 48(\base)
|
||||||
|
lw a4, 52(\base)
|
||||||
|
lw a5, 56(\base)
|
||||||
|
lw a6, 60(\base)
|
||||||
|
lw a7, 64(\base)
|
||||||
|
lw s2, 68(\base)
|
||||||
|
lw s3, 72(\base)
|
||||||
|
lw s4, 76(\base)
|
||||||
|
lw s5, 80(\base)
|
||||||
|
lw s6, 84(\base)
|
||||||
|
lw s7, 88(\base)
|
||||||
|
lw s8, 92(\base)
|
||||||
|
lw s9, 96(\base)
|
||||||
|
lw s10, 100(\base)
|
||||||
|
lw s11, 104(\base)
|
||||||
|
lw t3, 108(\base)
|
||||||
|
lw t4, 112(\base)
|
||||||
|
lw t5, 116(\base)
|
||||||
|
lw t6, 120(\base)
|
||||||
|
.endm
|
||||||
|
# ============ Macro END ==================
|
||||||
|
|
||||||
|
# Context switch
|
||||||
|
#
|
||||||
|
# void sys_switch(struct context *old, struct context *new);
|
||||||
|
#
|
||||||
|
# Save current registers in old. Load from new.
|
||||||
|
|
||||||
|
.globl sys_switch
|
||||||
|
.align 4
|
||||||
|
sys_switch:
|
||||||
|
|
||||||
|
ctx_save a0 # a0 => struct context *old
|
||||||
|
ctx_load a1 # a1 => struct context *new
|
||||||
|
ret # pc=ra; swtch to new task (new->ra)
|
||||||
|
|
||||||
|
.globl atomic_swap
|
||||||
|
.align 4
|
||||||
|
atomic_swap:
|
||||||
|
li a5, 1
|
||||||
|
amoswap.w.aq a5, a5, 0(a0)
|
||||||
|
mv a0, a5
|
||||||
|
ret
|
||||||
|
|
||||||
|
.globl trap_vector
|
||||||
|
# the trap vector base address must always be aligned on a 4-byte boundary
|
||||||
|
.align 4
|
||||||
|
trap_vector:
|
||||||
|
# save context(registers).
|
||||||
|
csrrw t6, mscratch, t6 # swap t6 and mscratch
|
||||||
|
reg_save t6
|
||||||
|
csrw mscratch, t6
|
||||||
|
# call the C trap handler in trap.c
|
||||||
|
csrr a0, mepc
|
||||||
|
csrr a1, mcause
|
||||||
|
call trap_handler
|
||||||
|
|
||||||
|
# trap_handler will return the return address via a0.
|
||||||
|
csrw mepc, a0
|
||||||
|
|
||||||
|
# load context(registers).
|
||||||
|
csrr t6, mscratch
|
||||||
|
reg_load t6
|
||||||
|
mret
|
||||||
|
|
||||||
32
07-ExterInterrupt/task.c
Normal file
32
07-ExterInterrupt/task.c
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "task.h"
|
||||||
|
#include "lib.h"
|
||||||
|
|
||||||
|
uint8_t task_stack[MAX_TASK][STACK_SIZE];
|
||||||
|
struct context ctx_os;
|
||||||
|
struct context ctx_tasks[MAX_TASK];
|
||||||
|
struct context *ctx_now;
|
||||||
|
int taskTop = 0; // total number of task
|
||||||
|
|
||||||
|
// create a new task
|
||||||
|
int task_create(void (*task)(void))
|
||||||
|
{
|
||||||
|
int i = taskTop++;
|
||||||
|
ctx_tasks[i].ra = (reg_t)task;
|
||||||
|
ctx_tasks[i].sp = (reg_t)&task_stack[i][STACK_SIZE - 1];
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch to task[i]
|
||||||
|
void task_go(int i)
|
||||||
|
{
|
||||||
|
ctx_now = &ctx_tasks[i];
|
||||||
|
sys_switch(&ctx_os, &ctx_tasks[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// switch back to os
|
||||||
|
void task_os()
|
||||||
|
{
|
||||||
|
struct context *ctx = ctx_now;
|
||||||
|
ctx_now = &ctx_os;
|
||||||
|
sys_switch(ctx, &ctx_os);
|
||||||
|
}
|
||||||
16
07-ExterInterrupt/task.h
Normal file
16
07-ExterInterrupt/task.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef __TASK_H__
|
||||||
|
#define __TASK_H__
|
||||||
|
|
||||||
|
#include "riscv.h"
|
||||||
|
#include "sys.h"
|
||||||
|
|
||||||
|
#define MAX_TASK 10
|
||||||
|
#define STACK_SIZE 1024
|
||||||
|
|
||||||
|
extern int taskTop;
|
||||||
|
|
||||||
|
extern int task_create(void (*task)(void));
|
||||||
|
extern void task_go(int i);
|
||||||
|
extern void task_os();
|
||||||
|
|
||||||
|
#endif
|
||||||
38
07-ExterInterrupt/timer.c
Normal file
38
07-ExterInterrupt/timer.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
// a scratch area per CPU for machine-mode timer interrupts.
|
||||||
|
reg_t timer_scratch[NCPU][5];
|
||||||
|
|
||||||
|
#define interval 20000000 // cycles; about 2 second in qemu.
|
||||||
|
|
||||||
|
void timer_init()
|
||||||
|
{
|
||||||
|
// each CPU has a separate source of timer interrupts.
|
||||||
|
int id = r_mhartid();
|
||||||
|
|
||||||
|
// ask the CLINT for a timer interrupt.
|
||||||
|
// int interval = 1000000; // cycles; about 1/10th second in qemu.
|
||||||
|
|
||||||
|
*(reg_t *)CLINT_MTIMECMP(id) = *(reg_t *)CLINT_MTIME + interval;
|
||||||
|
|
||||||
|
// prepare information in scratch[] for timervec.
|
||||||
|
// scratch[0..2] : space for timervec to save registers.
|
||||||
|
// scratch[3] : address of CLINT MTIMECMP register.
|
||||||
|
// scratch[4] : desired interval (in cycles) between timer interrupts.
|
||||||
|
reg_t *scratch = &timer_scratch[id][0];
|
||||||
|
scratch[3] = CLINT_MTIMECMP(id);
|
||||||
|
scratch[4] = interval;
|
||||||
|
w_mscratch((reg_t)scratch);
|
||||||
|
|
||||||
|
// enable machine-mode timer interrupts.
|
||||||
|
w_mie(r_mie() | MIE_MTIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int timer_count = 0;
|
||||||
|
|
||||||
|
void timer_handler()
|
||||||
|
{
|
||||||
|
lib_printf("timer_handler: %d\n", ++timer_count);
|
||||||
|
int id = r_mhartid();
|
||||||
|
*(reg_t *)CLINT_MTIMECMP(id) = *(reg_t *)CLINT_MTIME + interval;
|
||||||
|
}
|
||||||
12
07-ExterInterrupt/timer.h
Normal file
12
07-ExterInterrupt/timer.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __TIMER_H__
|
||||||
|
#define __TIMER_H__
|
||||||
|
|
||||||
|
#include "riscv.h"
|
||||||
|
#include "sys.h"
|
||||||
|
#include "lib.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
extern void timer_handler();
|
||||||
|
extern void timer_init();
|
||||||
|
|
||||||
|
#endif
|
||||||
74
07-ExterInterrupt/trap.c
Normal file
74
07-ExterInterrupt/trap.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "os.h"
|
||||||
|
extern void trap_vector();
|
||||||
|
extern void lib_isr(void);
|
||||||
|
|
||||||
|
void trap_init()
|
||||||
|
{
|
||||||
|
// set the machine-mode trap handler.
|
||||||
|
w_mtvec((reg_t)trap_vector);
|
||||||
|
|
||||||
|
// enable machine-mode interrupts.
|
||||||
|
w_mstatus(r_mstatus() | MSTATUS_MIE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void external_handler()
|
||||||
|
{
|
||||||
|
int irq = plic_claim();
|
||||||
|
|
||||||
|
if (irq == UART0_IRQ)
|
||||||
|
{
|
||||||
|
lib_isr();
|
||||||
|
}
|
||||||
|
else if (irq)
|
||||||
|
{
|
||||||
|
lib_printf("unexpected interrupt irq = %d\n", irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irq)
|
||||||
|
{
|
||||||
|
plic_complete(irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_t trap_handler(reg_t epc, reg_t cause)
|
||||||
|
{
|
||||||
|
reg_t return_pc = epc;
|
||||||
|
reg_t cause_code = cause & 0xfff;
|
||||||
|
|
||||||
|
if (cause & 0x80000000)
|
||||||
|
{
|
||||||
|
/* Asynchronous trap - interrupt */
|
||||||
|
switch (cause_code)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
lib_puts("software interruption!\n");
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
lib_puts("timer interruption!\n");
|
||||||
|
// disable machine-mode timer interrupts.
|
||||||
|
w_mie(~((~r_mie()) | (1 << 7)));
|
||||||
|
timer_handler();
|
||||||
|
return_pc = (reg_t)&os_kernel;
|
||||||
|
// enable machine-mode timer interrupts.
|
||||||
|
w_mie(r_mie() | MIE_MTIE);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
lib_puts("external interruption!\n");
|
||||||
|
external_handler();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lib_puts("unknown async exception!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Synchronous trap - exception */
|
||||||
|
lib_puts("Sync exceptions!\n");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* code */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return return_pc;
|
||||||
|
}
|
||||||
76
07-ExterInterrupt/user.c
Normal file
76
07-ExterInterrupt/user.c
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
int shared_var = 500;
|
||||||
|
|
||||||
|
lock_t lock;
|
||||||
|
|
||||||
|
void test()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int ch = lib_getc();
|
||||||
|
if (ch <= 127 && ch >= 0)
|
||||||
|
{
|
||||||
|
lib_putc(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_task0(void)
|
||||||
|
{
|
||||||
|
lib_puts("Task0: Created!\n");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
lib_puts("Task0: Running...\n");
|
||||||
|
lib_delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_task1(void)
|
||||||
|
{
|
||||||
|
lib_puts("Task1: Created!\n");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
lib_puts("Task1: Running...\n");
|
||||||
|
lib_delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_task2(void)
|
||||||
|
{
|
||||||
|
lib_puts("Task2: Created!\n");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 50; i++)
|
||||||
|
{
|
||||||
|
lock_acquire(&lock);
|
||||||
|
shared_var++;
|
||||||
|
lock_free(&lock);
|
||||||
|
lib_delay(100);
|
||||||
|
}
|
||||||
|
lib_printf("The value of shared_var is: %d \n", shared_var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_task3(void)
|
||||||
|
{
|
||||||
|
lib_puts("Task3: Created!\n");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
lib_puts("Tryin to get the lock... \n");
|
||||||
|
lock_acquire(&lock);
|
||||||
|
lib_puts("Get the lock!\n");
|
||||||
|
lock_free(&lock);
|
||||||
|
lib_delay(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_init()
|
||||||
|
{
|
||||||
|
task_create(&test);
|
||||||
|
// lock_init(&lock);
|
||||||
|
// task_create(&user_task0);
|
||||||
|
// task_create(&user_task1);
|
||||||
|
// task_create(&user_task2);
|
||||||
|
// task_create(&user_task3);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user