From a6368812911312d6e4faa70f00a5b67407548fad Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Fri, 17 Mar 2023 07:51:28 -0700 Subject: [PATCH 1/4] draft --- src/main/scala/Core/CSR.scala | 12 +++++++ src/main/scala/Core/instructions.scala | 1 + src/main/scala/Core/sleep.scala | 50 ++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 src/main/scala/Core/sleep.scala diff --git a/src/main/scala/Core/CSR.scala b/src/main/scala/Core/CSR.scala index aa377284..b7972635 100644 --- a/src/main/scala/Core/CSR.scala +++ b/src/main/scala/Core/CSR.scala @@ -340,6 +340,18 @@ class CSR(implicit val conf: FlexpretConfiguration) extends Module { } } + val sleeper = Module(new Sleeper()).io + sleeper.tid := 0.U + sleeper.wake := false.B + sleeper.valid := false.B + when (write && compare_addr(CSRs.sleeper)) { + sleeper.tid := io.rw.data_in >> 1 + sleeper.wake := io.rw.data_in(0) + sleeper.valid := true.B + data_out := sleeper.state + } + + // exception handling if (conf.exceptions) { when(io.exception) { diff --git a/src/main/scala/Core/instructions.scala b/src/main/scala/Core/instructions.scala index 3f4c7212..59cb997e 100644 --- a/src/main/scala/Core/instructions.scala +++ b/src/main/scala/Core/instructions.scala @@ -260,6 +260,7 @@ object CSRs { val tohost = 0x51e val fromhost = 0x51f val hwlock = 0x520 + val sleeper = 0x530 val cycle = 0xc00 val time = 0xc01 val instret = 0xc02 diff --git a/src/main/scala/Core/sleep.scala b/src/main/scala/Core/sleep.scala new file mode 100644 index 00000000..af16e419 --- /dev/null +++ b/src/main/scala/Core/sleep.scala @@ -0,0 +1,50 @@ +package flexpret.core + +import chisel3._ +import chisel3.util._ + + + +class SleeperIO(implicit val conf: FlexpretConfiguration) extends Bundle { + val valid = Input(Bool()) + val wake = Input(Bool()) + val tid = Input(UInt(conf.threadBits.W)) + val state = Output(UInt(2.W)) +} + + +class Sleeper(implicit val conf: FlexpretConfiguration) extends Module { + val io = IO(new SleeperIO()) + io.state := 3.U // invalid state + + val regAwake = RegInit(0.U(conf.threads.W)) + val regCaffeinated = RegInit(0.U(conf.threads.W)) + + val mask = 1.U(conf.threads.W) << io.tid + val awake = (regAwake & mask) =/= 0.U(conf.threads.W) + val caffeinated = (regCaffeinated & mask) =/= 0.U(conf.threads.W) + + when(io.valid) { + when(io.wake) { + when (awake || caffeinated) { // set state to caffeinated + regAwake := regAwake & (~mask) + regCaffeinated := regCaffeinated | mask + io.state := 2.U + } .otherwise { // set state to awake + regAwake := regAwake | mask + regCaffeinated := regCaffeinated & (~mask) + io.state := 1.U + } + }.otherwise { + when (caffeinated) { // set state to awake + regAwake := regAwake | mask + regCaffeinated := regCaffeinated & (~mask) + io.state := 1.U + } .otherwise { // set state to asleep + regAwake := regAwake & (~mask) + regCaffeinated := regCaffeinated & (~mask) + io.state := 0.U + } + } + } +} \ No newline at end of file From e87a5a83fe74f48cd6bb5b586660e7ae341221ba Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Fri, 31 Mar 2023 05:01:18 -0700 Subject: [PATCH 2/4] Makefiles, revert later --- programs/tests/c-tests/sleeper/Makefile | 4 ++++ programs/tests/c-tests/sleeper/sleeper.c | 14 ++++++++++++++ programs/tests/mt-c-tests/add/Makefile | 4 ++++ programs/tests/mt-c-tests/lockowner/Makefile | 4 ++++ programs/tests/mt-c-tests/swlock/Makefile | 4 ++++ programs/tests/mt-c-tests/threadcancel/Makefile | 4 ++++ 6 files changed, 34 insertions(+) create mode 100644 programs/tests/c-tests/sleeper/Makefile create mode 100644 programs/tests/c-tests/sleeper/sleeper.c create mode 100644 programs/tests/mt-c-tests/add/Makefile create mode 100644 programs/tests/mt-c-tests/lockowner/Makefile create mode 100644 programs/tests/mt-c-tests/swlock/Makefile create mode 100644 programs/tests/mt-c-tests/threadcancel/Makefile diff --git a/programs/tests/c-tests/sleeper/Makefile b/programs/tests/c-tests/sleeper/Makefile new file mode 100644 index 00000000..3dded651 --- /dev/null +++ b/programs/tests/c-tests/sleeper/Makefile @@ -0,0 +1,4 @@ +FLEXPRET_ROOT_DIR = ../../../../ +NAME = sleeper +APP_SOURCES = *.c +include $(FLEXPRET_ROOT_DIR)/Makefrag diff --git a/programs/tests/c-tests/sleeper/sleeper.c b/programs/tests/c-tests/sleeper/sleeper.c new file mode 100644 index 00000000..000222ce --- /dev/null +++ b/programs/tests/c-tests/sleeper/sleeper.c @@ -0,0 +1,14 @@ +#include +#include + +int main() { + + // Print the hardware thread id. + _fp_print(read_hartid()); + + _fp_print(read_csr(0x530)); + + _fp_print(1); + return 0; +} + diff --git a/programs/tests/mt-c-tests/add/Makefile b/programs/tests/mt-c-tests/add/Makefile new file mode 100644 index 00000000..44dce22c --- /dev/null +++ b/programs/tests/mt-c-tests/add/Makefile @@ -0,0 +1,4 @@ +FLEXPRET_ROOT_DIR = ../../../../ +NAME = add +APP_SOURCES = *.c +include $(FLEXPRET_ROOT_DIR)/Makefrag diff --git a/programs/tests/mt-c-tests/lockowner/Makefile b/programs/tests/mt-c-tests/lockowner/Makefile new file mode 100644 index 00000000..7102ea1c --- /dev/null +++ b/programs/tests/mt-c-tests/lockowner/Makefile @@ -0,0 +1,4 @@ +FLEXPRET_ROOT_DIR = ../../../../ +NAME = lockowner +APP_SOURCES = *.c +include $(FLEXPRET_ROOT_DIR)/Makefrag diff --git a/programs/tests/mt-c-tests/swlock/Makefile b/programs/tests/mt-c-tests/swlock/Makefile new file mode 100644 index 00000000..4b630f24 --- /dev/null +++ b/programs/tests/mt-c-tests/swlock/Makefile @@ -0,0 +1,4 @@ +FLEXPRET_ROOT_DIR = ../../../../ +NAME = swlock +APP_SOURCES = *.c +include $(FLEXPRET_ROOT_DIR)/Makefrag diff --git a/programs/tests/mt-c-tests/threadcancel/Makefile b/programs/tests/mt-c-tests/threadcancel/Makefile new file mode 100644 index 00000000..7150c418 --- /dev/null +++ b/programs/tests/mt-c-tests/threadcancel/Makefile @@ -0,0 +1,4 @@ +FLEXPRET_ROOT_DIR = ../../../../ +NAME = threadcancel +APP_SOURCES = *.c +include $(FLEXPRET_ROOT_DIR)/Makefrag From 9297ef49ec1c07984c02d91fff39ee08b6f84c01 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Fri, 21 Apr 2023 07:40:23 -0700 Subject: [PATCH 3/4] make sleep csr instructions actually sleep --- src/main/scala/Core/CSR.scala | 21 ++++++++--- src/main/scala/Core/instructions.scala | 3 +- src/main/scala/Core/sleep.scala | 52 +++++++++++--------------- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/main/scala/Core/CSR.scala b/src/main/scala/Core/CSR.scala index b7972635..c6ae7388 100644 --- a/src/main/scala/Core/CSR.scala +++ b/src/main/scala/Core/CSR.scala @@ -343,15 +343,26 @@ class CSR(implicit val conf: FlexpretConfiguration) extends Module { val sleeper = Module(new Sleeper()).io sleeper.tid := 0.U sleeper.wake := false.B - sleeper.valid := false.B - when (write && compare_addr(CSRs.sleeper)) { - sleeper.tid := io.rw.data_in >> 1 - sleeper.wake := io.rw.data_in(0) - sleeper.valid := true.B + sleeper.sleep := false.B + when (write && compare_addr(CSRs.wake)) { + sleeper.tid := io.rw.data_in + sleeper.wake := true.B data_out := sleeper.state + when (sleeper.state =/= 0.U) { + wake(io.rw.data_in) := true.B + } + } + when (write && compare_addr(CSRs.sleep)) { + sleeper.tid := io.rw.thread + sleeper.sleep := true.B + data_out := sleeper.state + when (sleeper.state === 0.U) { + sleep := true.B + } } + // exception handling if (conf.exceptions) { when(io.exception) { diff --git a/src/main/scala/Core/instructions.scala b/src/main/scala/Core/instructions.scala index 59cb997e..b8d101d7 100644 --- a/src/main/scala/Core/instructions.scala +++ b/src/main/scala/Core/instructions.scala @@ -260,7 +260,8 @@ object CSRs { val tohost = 0x51e val fromhost = 0x51f val hwlock = 0x520 - val sleeper = 0x530 + val sleep = 0x530 + val wake = 0x531 val cycle = 0xc00 val time = 0xc01 val instret = 0xc02 diff --git a/src/main/scala/Core/sleep.scala b/src/main/scala/Core/sleep.scala index af16e419..53f510a5 100644 --- a/src/main/scala/Core/sleep.scala +++ b/src/main/scala/Core/sleep.scala @@ -6,10 +6,10 @@ import chisel3.util._ class SleeperIO(implicit val conf: FlexpretConfiguration) extends Bundle { - val valid = Input(Bool()) val wake = Input(Bool()) + val sleep = Input(Bool()) val tid = Input(UInt(conf.threadBits.W)) - val state = Output(UInt(2.W)) + val state = Output(UInt(2.W)) // resulting state of tid } @@ -17,34 +17,26 @@ class Sleeper(implicit val conf: FlexpretConfiguration) extends Module { val io = IO(new SleeperIO()) io.state := 3.U // invalid state - val regAwake = RegInit(0.U(conf.threads.W)) - val regCaffeinated = RegInit(0.U(conf.threads.W)) - - val mask = 1.U(conf.threads.W) << io.tid - val awake = (regAwake & mask) =/= 0.U(conf.threads.W) - val caffeinated = (regCaffeinated & mask) =/= 0.U(conf.threads.W) - - when(io.valid) { - when(io.wake) { - when (awake || caffeinated) { // set state to caffeinated - regAwake := regAwake & (~mask) - regCaffeinated := regCaffeinated | mask - io.state := 2.U - } .otherwise { // set state to awake - regAwake := regAwake | mask - regCaffeinated := regCaffeinated & (~mask) - io.state := 1.U - } - }.otherwise { - when (caffeinated) { // set state to awake - regAwake := regAwake | mask - regCaffeinated := regCaffeinated & (~mask) - io.state := 1.U - } .otherwise { // set state to asleep - regAwake := regAwake & (~mask) - regCaffeinated := regCaffeinated & (~mask) - io.state := 0.U - } + val regStates = RegInit(VecInit(Seq.fill(conf.threads) { 1.U(2.W) })) + val awake = regStates(io.tid)(0); + val caffeinated = regStates(io.tid)(1); + + when(io.wake) { + when (awake || caffeinated) { // set state to caffeinated + regStates(io.tid) := 2.U + io.state := 2.U + } .otherwise { // set state to awake + regStates(io.tid) := 1.U + io.state := 1.U + } + } + when(io.sleep) { + when (caffeinated) { // set state to awake + regStates(io.tid) := 1.U + io.state := 1.U + } .otherwise { // set state to asleep + regStates(io.tid) := 0.U + io.state := 0.U } } } \ No newline at end of file From 8e4fb4bd4bc288a8aa2b1ee6b99ddecfeb188c27 Mon Sep 17 00:00:00 2001 From: Samuel Berkun Date: Fri, 28 Apr 2023 07:29:27 -0700 Subject: [PATCH 4/4] progress --- programs/lib/flexpret_lock.c | 25 ++++++++++++++++++++++-- programs/lib/flexpret_thread.c | 8 ++++---- programs/lib/include/flexpret.h | 1 + programs/lib/include/flexpret_lock.h | 4 +++- programs/lib/include/flexpret_sleep.h | 17 ++++++++++++++++ programs/tests/c-tests/sleeper/sleeper.c | 12 +++++++++--- src/main/scala/Core/sleep.scala | 15 ++++++++------ 7 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 programs/lib/include/flexpret_sleep.h diff --git a/programs/lib/flexpret_lock.c b/programs/lib/flexpret_lock.c index cb9b373d..b21a62b1 100644 --- a/programs/lib/flexpret_lock.c +++ b/programs/lib/flexpret_lock.c @@ -1,5 +1,12 @@ #include "flexpret.h" + +/* +linked list +*/ +static bool has_next_waiter[NUM_THREADS]; +static uint32_t next_waiter[NUM_THREADS]; + /** * Acquire a hardware lock. */ @@ -18,19 +25,25 @@ void hwlock_release() { } int do_acquire(lock_t* lock) { + uint32_t hartid = read_hartid(); hwlock_acquire(); if (lock->locked) { + // append to front of lock's linked list + has_next_waiter[hartid] = lock->has_first_waiter; + next_waiter[hartid] = lock->first_waiter; + lock->has_first_waiter = true; + lock->first_waiter = hartid; hwlock_release(); + fp_sleep(); // sleep until lock is availible return 1; } lock->locked = true; - lock->owner = read_hartid(); + lock->owner = hartid; hwlock_release(); return 0; } void lock_acquire(lock_t* lock) { - // Spin lock while(do_acquire(lock)); } @@ -45,5 +58,13 @@ void lock_release(lock_t* lock) { } lock->locked = false; lock->owner = UINT32_MAX; + if (lock->has_first_waiter) { + // pop first waiter off of linked list + uint32_t fw = lock->first_waiter; + lock->has_first_waiter = has_next_waiter[fw]; + lock->first_waiter = next_waiter[fw]; + // wake first waiter + fp_wake(fw); + } hwlock_release(); } diff --git a/programs/lib/flexpret_thread.c b/programs/lib/flexpret_thread.c index 1fc707df..a4694648 100644 --- a/programs/lib/flexpret_thread.c +++ b/programs/lib/flexpret_thread.c @@ -4,6 +4,7 @@ #include #include #include +#include /************************************************* * FlexPRET's hardware thread scheduling functions @@ -235,8 +236,7 @@ int thread_create( num_threads_busy += 1; // Signal the worker thread to do work. in_use[i] = true; - // FIXME: If the thread is asleep, - // wake up the thread. + fp_wake(i); hwlock_release(); return 0; } @@ -264,8 +264,7 @@ int thread_map( num_threads_busy += 1; // Signal the worker thread to do work. in_use[*hartid] = true; - // FIXME: If the thread is asleep, - // wake up the thread. + fp_wake(*hartid); hwlock_release(); return 0; } @@ -371,6 +370,7 @@ void worker_main() { num_threads_busy -= 1; in_use[hartid] = false; hwlock_release(); + fp_sleep(); } } diff --git a/programs/lib/include/flexpret.h b/programs/lib/include/flexpret.h index 500e2d7e..7122a746 100644 --- a/programs/lib/include/flexpret.h +++ b/programs/lib/include/flexpret.h @@ -5,6 +5,7 @@ #include "flexpret_csrs.h" #include "flexpret_io.h" #include "flexpret_lock.h" +#include "flexpret_sleep.h" #include "flexpret_thread.h" #include diff --git a/programs/lib/include/flexpret_lock.h b/programs/lib/include/flexpret_lock.h index e6bf1919..df6f3a84 100644 --- a/programs/lib/include/flexpret_lock.h +++ b/programs/lib/include/flexpret_lock.h @@ -4,10 +4,12 @@ #include #include -#define LOCK_INITIALIZER { .locked = false, .owner = UINT32_MAX } +#define LOCK_INITIALIZER { .locked = false, .owner = UINT32_MAX, .first_waiter = 0, .has_first_waiter = false } typedef struct _lock_t { bool locked; uint32_t owner; + bool has_first_waiter; + uint32_t first_waiter; } lock_t; /** diff --git a/programs/lib/include/flexpret_sleep.h b/programs/lib/include/flexpret_sleep.h new file mode 100644 index 00000000..1b14da95 --- /dev/null +++ b/programs/lib/include/flexpret_sleep.h @@ -0,0 +1,17 @@ +#ifndef FLEXPRET_SLEEP_H +#define FLEXPRET_SLEEP_H + +#include "flexpret_io.h" + +/** + * Put the current thread to sleep. + */ +static inline int fp_sleep() { return swap_csr(0x530, 0x0); } + +/** + * Wake up thread with given hartid + */ +static inline int fp_wake(uint32_t hartid) { return swap_csr(0x531, hartid); } + + +#endif // FLEXPRET_SLEEP_H diff --git a/programs/tests/c-tests/sleeper/sleeper.c b/programs/tests/c-tests/sleeper/sleeper.c index 000222ce..0aa43479 100644 --- a/programs/tests/c-tests/sleeper/sleeper.c +++ b/programs/tests/c-tests/sleeper/sleeper.c @@ -1,14 +1,20 @@ #include #include +#include "flexpret_sleep.h" int main() { // Print the hardware thread id. - _fp_print(read_hartid()); + int x = read_hartid(); + _fp_print(x); - _fp_print(read_csr(0x530)); + _fp_print(fp_wake(0x0)); + _fp_print(fp_wake(0x0)); + _fp_print(fp_wake(0x0)); + _fp_print(fp_sleep()); + // _fp_print(fp_sleep()); - _fp_print(1); + _fp_print(9); return 0; } diff --git a/src/main/scala/Core/sleep.scala b/src/main/scala/Core/sleep.scala index 53f510a5..a292c8b5 100644 --- a/src/main/scala/Core/sleep.scala +++ b/src/main/scala/Core/sleep.scala @@ -17,25 +17,28 @@ class Sleeper(implicit val conf: FlexpretConfiguration) extends Module { val io = IO(new SleeperIO()) io.state := 3.U // invalid state - val regStates = RegInit(VecInit(Seq.fill(conf.threads) { 1.U(2.W) })) - val awake = regStates(io.tid)(0); + // in regStates, 0 = awake, 1 = asleep, 2 = caffeinated + // (because initializing to non-zero is not possible?) + // in io.state, 0 = asleep, 1 = awake, 2 = caffeinated + val regStates = RegInit(VecInit(Seq.fill(conf.threads) { 0.U(2.W) })) + val asleep = regStates(io.tid)(0); val caffeinated = regStates(io.tid)(1); when(io.wake) { - when (awake || caffeinated) { // set state to caffeinated + when (!asleep) { // set state to caffeinated regStates(io.tid) := 2.U io.state := 2.U } .otherwise { // set state to awake - regStates(io.tid) := 1.U + regStates(io.tid) := 0.U io.state := 1.U } } when(io.sleep) { when (caffeinated) { // set state to awake - regStates(io.tid) := 1.U + regStates(io.tid) := 0.U io.state := 1.U } .otherwise { // set state to asleep - regStates(io.tid) := 0.U + regStates(io.tid) := 1.U io.state := 0.U } }