diff --git a/.bazelrc b/.bazelrc index 4d83ed1..c163027 100644 --- a/.bazelrc +++ b/.bazelrc @@ -6,13 +6,22 @@ build:host --copt='-DSUPRUGLUE_TEST32' # linker_files not working, can't sandbox the `ar` step build --spawn_strategy=standalone -build:clpru --crosstool_top=//tools/toolchain:clpru_suite -build:clpru --cpu=pru -build:clpru --host_crosstool_top=@bazel_tools//tools/cpp:toolchain -build:clpru --platforms //tools/toolchain:real_pru -build:clpru --copt='-DSUPRUGLUE_AM335X' -build:clpru --copt='--opt_level=4' -build:clpru --copt='--opt_for_speed=0' +build:pru0 --crosstool_top=//tools/toolchain:clpru_suite +build:pru0 --cpu=pru +build:pru0 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain +build:pru0 --platforms //tools/toolchain:real_pru +build:pru0 --copt='-DSUPRUGLUE_AM335X' +build:pru0 --copt='--opt_level=4' +build:pru0 --copt='--opt_for_speed=0' + +build:pru1 --crosstool_top=//tools/toolchain:clpru_suite +build:pru1 --cpu=pru +build:pru1 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain +build:pru1 --platforms //tools/toolchain:real_pru +build:pru1 --copt='-DSUPRUGLUE_AM335X' +build:pru1 --copt='-DSUPRUGLUE_PRU_NUM' +build:pru1 --copt='--opt_level=4' +build:pru1 --copt='--opt_for_speed=0' build:arm --platforms @io_bazel_rules_go//go/toolchain:linux_arm diff --git a/README.md b/README.md index a010305..1ee7438 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,10 @@ As space becomes tight, more space-optimization will likely be needed. ### Quickstart -To test the PRU build w/ TI's compiler: +To build PRU firmware with TI's compiler for PRU-0: ``` -bazel build --config=clpru ... +bazel build --config=pru0 ... ``` To test using a host toolchain: @@ -75,7 +75,7 @@ bazel build --config=arm ... The example will alternatingly flash two LEDs on pins `P9_23` and `P9_25`. ``` -bazel build --config=clpru //examples:example_pru0 +bazel build --config=pru0 //examples:example_pru0 ``` The firmware is located in `bazel-out/pru-fastbuild/bin/examples/example_pru0` diff --git a/examples/BUILD b/examples/BUILD index 9b71475..7b134ba 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -18,6 +18,8 @@ cc_binary( "//lib/initproc", "//lib/log/daemon", "//lib/rpmsg", + "//lib/time/clock:process", + #"//lib/ui1203", "//tools/toolchain/am335x", ], ) diff --git a/examples/example.c b/examples/example.c index b4b0b2c..15f3b5f 100644 --- a/examples/example.c +++ b/examples/example.c @@ -12,6 +12,8 @@ #include "lib/log/daemon/daemon.h" #include "lib/pinmap/pinmap.h" #include "lib/rpmsg/rpmsg.h" +#include "lib/time/clock/clock.h" +#include "lib/time/clock/process.h" #define NUM_RESOURCES 1 @@ -83,42 +85,40 @@ struct my_resource_table resourceTable = { }, }; -void test_write_func(ThreadID tid, Args args) { - int32_t i = 0; - for (;; i++) { - PRULOG_2U(INFO, "write %u", i, 0); // Logs always yield - } -} +#define BLUE_PERIOD 2000000000U +#define YELLOW_PERIOD 1000000000U void toggle_blue(ThreadID tid, Args args) { - gpio_pin pin = GPIO_PIN(P9_25); - + gpio_pin pin = GPIO_PIN(P9_23); + PRULOG_2U(INFO, "starting blue half-cycle %uns", BLUE_PERIOD, 0); while (1) { + PRULOG_2U(INFO, "blue on", 0, 0); + GPIO_SetPin(pin, 1); - __delay_cycles(100000000); - Yield(); + Sleep(BLUE_PERIOD); + + PRULOG_2U(INFO, "blue off", 0, 0); GPIO_SetPin(pin, 0); - __delay_cycles(100000000); - Yield(); + Sleep(BLUE_PERIOD); } } void toggle_yellow(ThreadID tid, Args args) { - gpio_pin pin = GPIO_PIN(P9_23); - + gpio_pin pin = GPIO_PIN(P9_25); + PRULOG_2U(INFO, "starting yellow half-cycle %uns", YELLOW_PERIOD, 0); while (1) { + PRULOG_2U(INFO, "yellow on", 0, 0); + GPIO_SetPin(pin, 1); - __delay_cycles(200000000); - Yield(); + Sleep(YELLOW_PERIOD); + PRULOG_2U(INFO, "yellow off", 0, 0); GPIO_SetPin(pin, 0); - __delay_cycles(200000000); - Yield(); + Sleep(YELLOW_PERIOD); } } -SUPRUGLUE_DEFINE_THREAD(writer, 256); SUPRUGLUE_DEFINE_THREAD(syslog, 256); SUPRUGLUE_DEFINE_THREAD(init, 256); SUPRUGLUE_DEFINE_THREAD(blue, 256); @@ -130,10 +130,10 @@ int main(void) { Args args2; int err = 0; - SystemOnChipSetup(); - Init(NewSystemConfig()); + ClockInit(); + err = RpmsgInit(&__transport, &resourceTable.rpmsg_vdev, &resourceTable.rpmsg_vring0, &resourceTable.rpmsg_vring1); if (err != 0) { // @@@ this has failed b/c wrong event number... what would we do? @@ -145,10 +145,9 @@ int main(void) { err = Create(&init.thread, InitProcess, args1, "init", sizeof(init.space)); err = Create(&syslog.thread, SyslogProcess, args2, "syslog", sizeof(syslog.space)); - err = Create(&writer.thread, test_write_func, args1, "writer", sizeof(writer.space)); - // err = Create(&blue.thread, toggle_blue, args2, "blue", sizeof(blue.space)); - // err = Create(&yellow.thread, toggle_yellow, args2, "yellow", sizeof(yellow.space)); + err = Create(&blue.thread, toggle_blue, args2, "blue", sizeof(blue.space)); + err = Create(&yellow.thread, toggle_yellow, args2, "yellow", sizeof(yellow.space)); err = Run(); return err; diff --git a/lib/coroutine/coroutine.c b/lib/coroutine/coroutine.c index d0edabd..07e72de 100755 --- a/lib/coroutine/coroutine.c +++ b/lib/coroutine/coroutine.c @@ -22,6 +22,7 @@ int Init(SystemConfig cfg) { System *sys = &__system; memset(sys, 0, sizeof(*sys)); sys->cfg = cfg; + SystemOnChipSetup(); ThreadListInit(&__system_runnable); JournalInit(&sys->journal); ControllerInit(&__controller); @@ -40,7 +41,7 @@ int Create(Thread *thread, ThreadFunc *func, Args args, const char *name, size_t } int __run(void) { - while (!ThreadListEmpty(&__system_runnable)) { + while (!SystemOnChipIsShutdown() && !ThreadListEmpty(&__system_runnable)) { ServiceInterrupts(&__controller); Thread *volatile run = ThreadListPopFront(&__system_runnable); diff --git a/lib/debug/debug.c b/lib/debug/debug.c index fa42e61..205d4b5 100644 --- a/lib/debug/debug.c +++ b/lib/debug/debug.c @@ -6,10 +6,10 @@ #include "lib/pinmap/pinmap.h" #include "lib/soc/soc.h" -const gpio_pin _uled1 = GPIO_PIN_STRUCT(ULED1); -const gpio_pin _uled2 = GPIO_PIN_STRUCT(ULED2); -const gpio_pin _uled3 = GPIO_PIN_STRUCT(ULED3); -const gpio_pin _uled4 = GPIO_PIN_STRUCT(ULED4); +gpio_pin _uled1 = GPIO_PIN_STRUCT(ULED1); +gpio_pin _uled2 = GPIO_PIN_STRUCT(ULED2); +gpio_pin _uled3 = GPIO_PIN_STRUCT(ULED3); +gpio_pin _uled4 = GPIO_PIN_STRUCT(ULED4); void uled1(int val) { GPIO_SetPin(_uled1, val); diff --git a/lib/gpio/test32/gpio.cc b/lib/gpio/test32/gpio.cc index d28dd1a..cebb986 100644 --- a/lib/gpio/test32/gpio.cc +++ b/lib/gpio/test32/gpio.cc @@ -5,7 +5,12 @@ #include "gpio.h" -void GPIO_SetRegister(gpio_bank *g, int r, uint32_t v) { +static uint32_t __gpio_banks[4]; + +void GPIO_SetRegister(gpio_bank *as_int, int r, uint32_t v) { + intptr_t num = ((intptr_t)as_int) - 1; + gpio_bank *g = &__gpio_banks[num]; + switch (r) { case GPIOREG_CLEARDATAOUT: *g &= ~v; @@ -24,7 +29,10 @@ void GPIO_SetRegister(gpio_bank *g, int r, uint32_t v) { } } -uint32_t GPIO_GetRegister(gpio_bank *g, int r) { +uint32_t GPIO_GetRegister(gpio_bank *as_int, int r) { + intptr_t num = ((intptr_t)as_int) - 1; + gpio_bank *g = &__gpio_banks[num]; + switch (r) { case GPIOREG_DATAOUT: return *g; diff --git a/lib/gpio/test32/gpio.h b/lib/gpio/test32/gpio.h index 4639499..304c00a 100644 --- a/lib/gpio/test32/gpio.h +++ b/lib/gpio/test32/gpio.h @@ -13,10 +13,10 @@ extern "C" { #endif -#define GPIO_BANK0 ((gpio_bank *)(&__soc->gpio_banks[0])) -#define GPIO_BANK1 ((gpio_bank *)(&__soc->gpio_banks[1])) -#define GPIO_BANK2 ((gpio_bank *)(&__soc->gpio_banks[2])) -#define GPIO_BANK3 ((gpio_bank *)(&__soc->gpio_banks[3])) +#define GPIO_BANK0 ((gpio_bank *)1) +#define GPIO_BANK1 ((gpio_bank *)2) +#define GPIO_BANK2 ((gpio_bank *)3) +#define GPIO_BANK3 ((gpio_bank *)4) #ifdef __cplusplus } diff --git a/lib/gpio/test32/gpio_test.cc b/lib/gpio/test32/gpio_test.cc index c4dff3b..6a276a2 100644 --- a/lib/gpio/test32/gpio_test.cc +++ b/lib/gpio/test32/gpio_test.cc @@ -13,7 +13,7 @@ class GpioTest : public testing::Test { } void TearDown() override { - SystemOnChipTeardown(); + SystemOnChipShutdown(); } }; diff --git a/lib/initproc/initproc.c b/lib/initproc/initproc.c index c65816c..0773c52 100644 --- a/lib/initproc/initproc.c +++ b/lib/initproc/initproc.c @@ -23,7 +23,7 @@ void InitProcess(ThreadID thid, Args args) { // TODO: otherwise, not clear what kind of fallback reporting // can be done when a permanent error (PRU_RPMSG_INVALID_HEAD) // is returned. Try again! - flash(4); + // flash(4); Yield(); } Yield(); diff --git a/lib/intc/am335x/BUILD b/lib/intc/am335x/BUILD index 1913ca3..be92d5f 100644 --- a/lib/intc/am335x/BUILD +++ b/lib/intc/am335x/BUILD @@ -12,5 +12,6 @@ cc_library( deps = [ "//lib/debug", "//lib/intc:defs", + "//tools/toolchain/am335x", ], ) diff --git a/lib/intc/am335x/intc.c b/lib/intc/am335x/intc.c index dd3723a..c429c44 100644 --- a/lib/intc/am335x/intc.c +++ b/lib/intc/am335x/intc.c @@ -1,3 +1,4 @@ + // Copyright Joshua MacDonald // SPDX-License-Identifier: MIT @@ -37,10 +38,10 @@ void ServiceInterrupts(InterruptController *controller) { CT_INTC.SECR0 |= (1 << SYSEVT_PR1_PRU_MST_INTR1_INTR_REQ); } else { - if (CT_INTC.HIPIR0 & (1 << 31)) { - // @@@??? - } else { - } + // if (CT_INTC.HIPIR0 & (1 << 31)) { + // // @@@??? + // } else { + // } } // Unblock all and prioritize to run immediately. diff --git a/lib/intc/intc-defs.h b/lib/intc/intc-defs.h index daf1ff6..b64e731 100644 --- a/lib/intc/intc-defs.h +++ b/lib/intc/intc-defs.h @@ -12,7 +12,7 @@ typedef struct _InterruptController InterruptController; extern InterruptController __controller; -void InitController(InterruptController *controller); +void ControllerInit(InterruptController *controller); void ServiceInterrupts(InterruptController *controller); diff --git a/lib/intc/test32/BUILD b/lib/intc/test32/BUILD index b1f82f9..89209e8 100644 --- a/lib/intc/test32/BUILD +++ b/lib/intc/test32/BUILD @@ -4,7 +4,7 @@ package(default_visibility = ["//visibility:public"]) cc_library( name = "test32", srcs = [ - # "intc.cc", + "intc.cc", ], hdrs = [ "intc.h", diff --git a/lib/intc/test32/intc.cc b/lib/intc/test32/intc.cc new file mode 100644 index 0000000..2951fd0 --- /dev/null +++ b/lib/intc/test32/intc.cc @@ -0,0 +1,15 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#include "lib/intc/test32/intc.h" + +InterruptController __controller; + +void ControllerInit(InterruptController *controller) { +} + +void ServiceInterrupts(InterruptController *controller) { +} + +void BlockOnHost0(InterruptController *controller) { +} diff --git a/lib/intc/test32/intc.h b/lib/intc/test32/intc.h index 5926faf..23f79f6 100644 --- a/lib/intc/test32/intc.h +++ b/lib/intc/test32/intc.h @@ -4,11 +4,16 @@ #ifndef LIB_INTC_TEST32_INTC_H #define LIB_INTC_TEST32_INTC_H +#include "lib/intc/intc-defs.h" +#include + #ifdef __cplusplus extern "C" { #endif -#include "lib/intc/intc-defs.h" +struct _InterruptController { + int32_t unused; +}; #ifdef __cplusplus } diff --git a/lib/list/BUILD b/lib/list/BUILD index 70f61d6..325fa2c 100644 --- a/lib/list/BUILD +++ b/lib/list/BUILD @@ -1,11 +1,15 @@ # -*- Mode: Python -*- package(default_visibility = ["//visibility:public"]) +# Note: the generic implementation is currently ~300 bytes larger. +# Re-evaluate. See ./save/list-old.h. cc_library( name = "list", hdrs = [ "list.h", ], + srcs = [ + ], ) cc_test( diff --git a/lib/list/list.h b/lib/list/list.h index 834822e..5c16f92 100644 --- a/lib/list/list.h +++ b/lib/list/list.h @@ -25,9 +25,7 @@ extern "C" { struct _##LTYPE { \ LTYPE *next; \ LTYPE *prev; \ - }; \ - \ - size_t LTYPE##Length(LTYPE *l); + }; #define SUPRUGLUE_DEFINE_LIST_INLINE(LTYPE, ETYPE, LNAME) \ \ @@ -82,18 +80,7 @@ extern "C" { \ static inline void LTYPE##PushFront(LTYPE *l, ETYPE *i) { LTYPE##Add(l, l->next, &i->LNAME); } -#define SUPRUGLUE_DEFINE_LIST(LTYPE, ETYPE, LNAME) \ - \ - size_t LTYPE##Length(LTYPE *l) { \ - LTYPE *p; \ - size_t c = 0; \ - \ - for (p = l->next; p != l; p = p->next) { \ - c += 1; \ - } \ - \ - return c; \ - } +#define SUPRUGLUE_DEFINE_LIST(LTYPE, ETYPE, LNAME) #ifdef __cplusplus } diff --git a/lib/list/list_test.cc b/lib/list/list_test.cc index 2303bfb..6d6b2e4 100644 --- a/lib/list/list_test.cc +++ b/lib/list/list_test.cc @@ -4,6 +4,10 @@ #include "lib/list/list.h" #include "gtest/gtest.h" +#include + +using std::vector; + typedef struct _Thing Thing; SUPRUGLUE_DECLARE_LIST(ThingList, Thing); @@ -17,11 +21,21 @@ SUPRUGLUE_DEFINE_LIST_INLINE(ThingList, Thing, L); SUPRUGLUE_DEFINE_LIST(ThingList, Thing, L); -TEST(ListTest, Basic) { +vector l2v(ThingList *l) { + vector v; + ThingList *p; + for (p = l->next; p != l; p = p->next) { + v.push_back(ThingListEntry(p)->X); + } + + return v; +} + +TEST(ListTest, PushBackRemove) { ThingList l; ThingListInit(&l); - EXPECT_EQ(0, ThingListLength(&l)); + EXPECT_EQ(1, ThingListEmpty(&l)); Thing t1{.X = 1}; Thing t2{.X = 2}; @@ -30,11 +44,93 @@ TEST(ListTest, Basic) { ThingListPushBack(&l, &t2); ThingListPushBack(&l, &t3); - EXPECT_EQ(3, ThingListLength(&l)); + EXPECT_EQ(0, ThingListEmpty(&l)); + + EXPECT_EQ((vector{1, 2, 3}), l2v(&l)); + EXPECT_EQ(1, ThingListFront(&l)->X); + EXPECT_EQ(3, ThingListBack(&l)->X); ThingListRemove(&t2); - EXPECT_EQ(2, ThingListLength(&l)); + EXPECT_EQ((vector{1, 3}), l2v(&l)); EXPECT_EQ(1, ThingListFront(&l)->X); EXPECT_EQ(3, ThingListBack(&l)->X); + + ThingListRemove(&t1); + + EXPECT_EQ((vector{3}), l2v(&l)); + EXPECT_EQ(3, ThingListFront(&l)->X); + EXPECT_EQ(3, ThingListBack(&l)->X); + + ThingListRemove(&t3); + + EXPECT_EQ((vector{}), l2v(&l)); + EXPECT_EQ(1, ThingListEmpty(&l)); +} + +TEST(ListTest, PushFrontPop) { + ThingList l; + ThingListInit(&l); + + EXPECT_EQ(1, ThingListEmpty(&l)); + + Thing t1{.X = 1}; + Thing t2{.X = 2}; + Thing t3{.X = 3}; + ThingListPushFront(&l, &t1); + ThingListPushFront(&l, &t2); + ThingListPushFront(&l, &t3); + + EXPECT_EQ(0, ThingListEmpty(&l)); + + EXPECT_EQ((vector{3, 2, 1}), l2v(&l)); + EXPECT_EQ(3, ThingListFront(&l)->X); + EXPECT_EQ(1, ThingListBack(&l)->X); + + EXPECT_EQ(&t3, ThingListPopFront(&l)); + + EXPECT_EQ((vector{2, 1}), l2v(&l)); + EXPECT_EQ(2, ThingListFront(&l)->X); + EXPECT_EQ(1, ThingListBack(&l)->X); + + EXPECT_EQ(&t1, ThingListPopBack(&l)); + + EXPECT_EQ((vector{2}), l2v(&l)); + EXPECT_EQ(2, ThingListFront(&l)->X); + EXPECT_EQ(2, ThingListBack(&l)->X); + + EXPECT_EQ(&t2, ThingListPopFront(&l)); + + EXPECT_EQ((vector{}), l2v(&l)); + EXPECT_EQ(1, ThingListEmpty(&l)); +} + +TEST(ListTest, Iterate) { + ThingList l; + ThingListInit(&l); + + Thing t1{.X = 1}; + Thing t2{.X = 2}; + Thing t3{.X = 3}; + ThingListPushFront(&l, &t1); + ThingListPushFront(&l, &t2); + ThingListPushFront(&l, &t3); + + EXPECT_EQ(&t3, ThingListFront(&l)); + EXPECT_EQ(&t2, ThingListNext(ThingListFront(&l))); + EXPECT_EQ(&t1, ThingListNext(ThingListNext(ThingListFront(&l)))); + + EXPECT_EQ(0, ThingListEnd(&l, ThingListFront(&l))); + EXPECT_EQ(0, ThingListEnd(&l, ThingListNext(ThingListFront(&l)))); + EXPECT_EQ(0, ThingListEnd(&l, ThingListNext(ThingListNext(ThingListFront(&l))))); + EXPECT_EQ(1, ThingListEnd(&l, ThingListNext(ThingListNext(ThingListNext(ThingListFront(&l)))))); + + EXPECT_EQ(&t1, ThingListBack(&l)); + EXPECT_EQ(&t2, ThingListPrev(ThingListBack(&l))); + EXPECT_EQ(&t3, ThingListPrev(ThingListPrev(ThingListBack(&l)))); + + EXPECT_EQ(0, ThingListEnd(&l, ThingListBack(&l))); + EXPECT_EQ(0, ThingListEnd(&l, ThingListPrev(ThingListBack(&l)))); + EXPECT_EQ(0, ThingListEnd(&l, ThingListPrev(ThingListPrev(ThingListBack(&l))))); + EXPECT_EQ(1, ThingListEnd(&l, ThingListPrev(ThingListPrev(ThingListPrev(ThingListBack(&l)))))); } diff --git a/lib/list/save/generic.c b/lib/list/save/generic.c new file mode 100644 index 0000000..2e73673 --- /dev/null +++ b/lib/list/save/generic.c @@ -0,0 +1,78 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#include "generic.h" + +void AnyListInit(AnyList *l) { + l->next = l; + l->prev = l; +} + +void AnyListDelete(AnyList *next, AnyList *prev) { + // @@@ TODO the following + next->prev->next = NULL; + next->prev->prev = NULL; + + next->prev = prev; + prev->next = next; +} + +void *AnyListEntry(AnyList *list, ptrdiff_t offset) { + return (void *)(((uint8_t *)list) - offset); +} + +AnyList *AnyListAtOffset(void *item, ptrdiff_t offset) { + return (AnyList *)(((uint8_t *)item) + offset); +} + +int AnyListEmpty(AnyList *list) { + return list == list->next; +} + +void *AnyListFront(AnyList *list, ptrdiff_t offset) { + return AnyListEntry(list->next, offset); +} + +void *AnyListBack(AnyList *list, ptrdiff_t offset) { + return AnyListEntry(list->prev, offset); +} + +void *AnyListNext(void *item, ptrdiff_t offset) { + return AnyListFront(AnyListAtOffset(item, offset), offset); +} + +void *AnyListPrev(void *item, ptrdiff_t offset) { + return AnyListBack(AnyListAtOffset(item, offset), offset); +} + +void AnyListPushBack(AnyList *list, void *item, ptrdiff_t offset) { + AnyListAdd(list->prev, list, AnyListAtOffset(item, offset)); +} + +void AnyListPushFront(AnyList *list, void *item, ptrdiff_t offset) { + AnyListAdd(list, list->next, AnyListAtOffset(item, offset)); +} + +void AnyListRemove(void *item, ptrdiff_t offset) { + AnyList *list = AnyListAtOffset(item, offset); + AnyListDelete(list->next, list->prev); +} + +void AnyListAdd(AnyList *prev, AnyList *next, AnyList *ins) { + next->prev = ins; + prev->next = ins; + ins->next = next; + ins->prev = prev; +} + +void *AnyListPopFront(AnyList *list, ptrdiff_t offset) { + AnyList *next = list->next; + AnyListDelete(next->next, list); + return AnyListEntry(next, offset); +} + +void *AnyListPopBack(AnyList *list, ptrdiff_t offset) { + AnyList *prev = list->prev; + AnyListDelete(list, prev->prev); + return AnyListEntry(prev, offset); +} diff --git a/lib/list/save/generic.h b/lib/list/save/generic.h new file mode 100644 index 0000000..6f09f37 --- /dev/null +++ b/lib/list/save/generic.h @@ -0,0 +1,43 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#ifndef LIB_LIST_GENERIC_H +#define LIB_LIST_GENERIC_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _AnyList AnyList; + +struct _AnyList { + AnyList *next; + AnyList *prev; +}; + +void AnyListInit(AnyList *l); +AnyList *AnyListAtOffset(void *item, ptrdiff_t offset); +int AnyListEmpty(AnyList *list); +void AnyListAdd(AnyList *prev, AnyList *next, AnyList *ins); +void AnyListDelete(AnyList *next, AnyList *prev); +void AnyListPushBack(AnyList *list, void *item, ptrdiff_t offset); +void AnyListPushBack(AnyList *list, void *item, ptrdiff_t offset); +void AnyListPushFront(AnyList *list, void *item, ptrdiff_t offset); +void AnyListPushFront(AnyList *list, void *item, ptrdiff_t offset); +void AnyListRemove(void *item, ptrdiff_t offset); +void *AnyListBack(AnyList *list, ptrdiff_t offset); +void *AnyListEntry(AnyList *list, ptrdiff_t offset); +void *AnyListFront(AnyList *list, ptrdiff_t offset); +void *AnyListNext(void *item, ptrdiff_t offset); +void *AnyListPopBack(AnyList *list, ptrdiff_t offset); +void *AnyListPopFront(AnyList *list, ptrdiff_t offset); +void *AnyListPrev(void *item, ptrdiff_t offset); + +#ifdef __cplusplus +} +#endif + +#endif // LIB_LIST_GENERIC_H diff --git a/lib/list/save/list.h b/lib/list/save/list.h new file mode 100644 index 0000000..0fb07de --- /dev/null +++ b/lib/list/save/list.h @@ -0,0 +1,81 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#ifndef LIB_LIST_LIST_H +#define LIB_LIST_LIST_H + +#include "generic.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Note: The definitions here have been inlined because it reduces +// program size, however another experiment count be done--there are +// currently two list definitions with nearly identical code. They +// can be abstracted to use the LinkOffset() method as an argument, +// and thus have one definition per method. With inline functions +// this seems to help, but possibly half as many non-inline functions +// is better. + +#define SUPRUGLUE_DECLARE_LIST(LTYPE, ETYPE) \ + \ + typedef struct _##LTYPE LTYPE; \ + \ + struct _##LTYPE { \ + LTYPE *next; \ + LTYPE *prev; \ + } + +#define SUPRUGLUE_DEFINE_LIST_INLINE(LTYPE, ETYPE, LNAME) \ + \ + static inline AnyList *LTYPE##_AL(LTYPE *list) { return (AnyList *)list; } \ + \ + static inline ptrdiff_t LTYPE##_LO() { return (ptrdiff_t) & ((ETYPE *)0)->LNAME; } \ + \ + static inline void LTYPE##Init(LTYPE *list) { AnyListInit(LTYPE##_AL(list)); } \ + \ + static inline void LTYPE##Delete(LTYPE *next, LTYPE *prev) { AnyListDelete(LTYPE##_AL(next), LTYPE##_AL(prev)); } \ + \ + static inline void LTYPE##Add(LTYPE *prev, LTYPE *next, LTYPE *insert) { \ + AnyListAdd(LTYPE##_AL(prev), LTYPE##_AL(next), LTYPE##_AL(insert)); \ + } \ + \ + static inline ETYPE *LTYPE##Entry(LTYPE *list) { return (ETYPE *)AnyListEntry(LTYPE##_AL(list), LTYPE##_LO()); } \ + \ + static inline int LTYPE##Empty(LTYPE *list) { return AnyListEmpty(LTYPE##_AL(list)); } \ + \ + static inline ETYPE *LTYPE##Next(ETYPE *item) { return (ETYPE *)AnyListNext(item, LTYPE##_LO()); } \ + \ + static inline ETYPE *LTYPE##Prev(ETYPE *item) { return (ETYPE *)AnyListPrev(item, LTYPE##_LO()); } \ + \ + static inline ETYPE *LTYPE##Front(LTYPE *list) { return (ETYPE *)AnyListFront(LTYPE##_AL(list), LTYPE##_LO()); } \ + \ + static inline ETYPE *LTYPE##End(LTYPE *list) { return (ETYPE *)AnyListEnd(LTYPE##_AL(list), LTYPE##_LO()); } \ + \ + static inline ETYPE *LTYPE##Back(LTYPE *list) { return (ETYPE *)AnyListBack(LTYPE##_AL(list), LTYPE##_LO()); } \ + \ + static inline void LTYPE##Remove(ETYPE *item) { AnyListRemove(item, LTYPE##_LO()); } \ + \ + static inline ETYPE *LTYPE##PopFront(LTYPE *list) { \ + return (ETYPE *)AnyListPopFront(LTYPE##_AL(list), LTYPE##_LO()); \ + } \ + \ + static inline ETYPE *LTYPE##PopBack(LTYPE *list) { return (ETYPE *)AnyListPopBack(LTYPE##_AL(list), LTYPE##_LO()); } \ + \ + static inline void LTYPE##PushBack(LTYPE *list, ETYPE *item) { \ + AnyListPushBack(LTYPE##_AL(list), item, LTYPE##_LO()); \ + } \ + \ + static inline void LTYPE##PushFront(LTYPE *list, ETYPE *item) { \ + AnyListPushFront(LTYPE##_AL(list), item, LTYPE##_LO()); \ + } + +#define SUPRUGLUE_DEFINE_LIST(LTYPE, ETYPE, LNAME) + +#ifdef __cplusplus +} +#endif + +#endif // LIB_LIST_LIST_H diff --git a/lib/log/daemon/daemon.c b/lib/log/daemon/daemon.c index 57c5264..310324d 100644 --- a/lib/log/daemon/daemon.c +++ b/lib/log/daemon/daemon.c @@ -30,7 +30,7 @@ void SyslogProcess(ThreadID thid, Args args) { // TODO: otherwise, not clear what kind of fallback reporting // can be done when a permanent error is returned. - flash(4); + // flash(4); Yield(); } diff --git a/lib/log/daemon/daemon_test.cc b/lib/log/daemon/daemon_test.cc index 8d644a3..9f93054 100644 --- a/lib/log/daemon/daemon_test.cc +++ b/lib/log/daemon/daemon_test.cc @@ -74,7 +74,6 @@ TEST(Syslog, Simple) { // Make sure the logs we received were all expected for (auto arg : res) { - cerr << arg << endl; EXPECT_NE(expect.end(), expect.find(arg)); } } diff --git a/lib/log/journal/BUILD b/lib/log/journal/BUILD index 2ebb821..0a1e36d 100644 --- a/lib/log/journal/BUILD +++ b/lib/log/journal/BUILD @@ -14,6 +14,7 @@ cc_library( "//lib/list", "//lib/sync", "//lib/thread", + "//lib/time/clock", ], ) diff --git a/lib/log/journal/journal.c b/lib/log/journal/journal.c index 3b438f4..641c6b9 100644 --- a/lib/log/journal/journal.c +++ b/lib/log/journal/journal.c @@ -4,6 +4,7 @@ #include "lib/log/journal/journal.h" #include "lib/debug/debug.h" #include "lib/sync/sync.h" +#include "lib/time/clock/clock.h" #include #include @@ -11,9 +12,6 @@ SUPRUGLUE_DEFINE_LIST(BlockList, Block, list); const char *const overflowMessage = "** OVERFLOW **: dropped %u records"; -// The ThreadID that shows for the overflow message -#define OVERFLOW_THREAD_ID 0xd - void JournalInit(Journal *jl) { memset(jl, 0, sizeof(*jl)); LockInit(&jl->lock); @@ -98,6 +96,7 @@ void JournalWrite(Journal *jl, ThreadID tid, const char *msg, int32_t arg1, int3 entry->msg = msg; entry->arg1 = arg1; entry->arg2 = arg2; + ReadClock(&entry->time); SemaUp(&jl->lock); diff --git a/lib/log/journal/journal.h b/lib/log/journal/journal.h index f635d5f..cd9e371 100644 --- a/lib/log/journal/journal.h +++ b/lib/log/journal/journal.h @@ -13,6 +13,9 @@ extern "C" { #endif +// The ThreadID that shows for the overflow message +#define OVERFLOW_THREAD_ID 0xd + extern const char *const overflowMessage; typedef struct _Journal Journal; @@ -32,17 +35,19 @@ enum _JournalReadFlags { enum _JournalWriteFlags { JW_NONE = 0, JW_YIELD = 0x1, + JW_INFO_BLOCK = 0x10, // INFO will Block JW_INFO = 0x10 | JW_YIELD, // INFO will Yield + JW_WARNING_BLOCK = 0x20, // WARNING will Block JW_WARNING = 0x20 | JW_YIELD, // WARNING will Yield - JW_FATAL = 0x40, // FATAL will not Yield + JW_FATAL = 0x40, // FATAL will Block }; typedef enum _JournalReadFlags JournalReadFlags; typedef enum _JournalWriteFlags JournalWriteFlags; struct _Entry { - // TODO: timestamp ThreadID tid; + Timestamp time; const char *msg; int32_t arg1; int32_t arg2; diff --git a/lib/log/journal/journal_test.cc b/lib/log/journal/journal_test.cc index f3b60c0..27dcb10 100644 --- a/lib/log/journal/journal_test.cc +++ b/lib/log/journal/journal_test.cc @@ -26,7 +26,7 @@ void testRead(Journal *jl, int32_t i) { void testReadOverflow(Journal *jl, int32_t i) { Entry entry; EXPECT_EQ(0, JournalRead(jl, &entry, JR_NONE)); - EXPECT_EQ(0, entry.tid); + EXPECT_EQ(OVERFLOW_THREAD_ID, entry.tid); EXPECT_STREQ(overflowMessage, entry.msg); EXPECT_EQ(i, entry.arg1); EXPECT_EQ(0, entry.arg2); diff --git a/lib/rpmsg/am335x/rpmsg.c b/lib/rpmsg/am335x/rpmsg.c index 7d669c6..5257bdb 100644 --- a/lib/rpmsg/am335x/rpmsg.c +++ b/lib/rpmsg/am335x/rpmsg.c @@ -61,16 +61,15 @@ int RpmsgInit(ClientTransport *transport, struct fw_rsc_vdev *vdev, struct fw_rs } // The system events and port are core-specific. - // if (PRU_CORE_NUMBER() == 0) { - // @@@ This is wrong!!! +#if SUPRUGLUE_PRU_NUM == 0 transport->channel_port = RPMSG_CHANNEL_PORT_0; transport->sysevt_pru_to_arm = SYSEVT_PR1_PRU_MST_INTR0_INTR_REQ; transport->sysevt_arm_to_pru = SYSEVT_PR1_PRU_MST_INTR1_INTR_REQ; - // } else { - // transport->channel_port = RPMSG_CHANNEL_PORT_1; - // transport->sysevt_pru_to_arm = SYSEVT_PR1_PRU_MST_INTR2_INTR_REQ; - // transport->sysevt_arm_to_pru = SYSEVT_PR1_PRU_MST_INTR3_INTR_REQ; - // } +#else + transport->channel_port = RPMSG_CHANNEL_PORT_1; + transport->sysevt_pru_to_arm = SYSEVT_PR1_PRU_MST_INTR2_INTR_REQ; + transport->sysevt_arm_to_pru = SYSEVT_PR1_PRU_MST_INTR3_INTR_REQ; +#endif int ret; ret = pru_rpmsg_init(&transport->channel, vring0, vring1, transport->sysevt_pru_to_arm, transport->sysevt_arm_to_pru); diff --git a/lib/rpmsg/test32/rpmsg.h b/lib/rpmsg/test32/rpmsg.h index 8debc44..612650a 100644 --- a/lib/rpmsg/test32/rpmsg.h +++ b/lib/rpmsg/test32/rpmsg.h @@ -19,6 +19,7 @@ extern "C" { #include "lib/rpmsg/rpmsg-defs.h" #define PRU_RPMSG_NO_BUF_AVAILABLE -7 +#define PRU_RPMSG_NO_PEER_ADDR -8 typedef struct _TestTransport TestTransport; diff --git a/lib/soc/am335x/soc.c b/lib/soc/am335x/soc.c index d6c9fc3..c28bebf 100644 --- a/lib/soc/am335x/soc.c +++ b/lib/soc/am335x/soc.c @@ -10,6 +10,3 @@ void SystemOnChipSetup(void) { // Allow OCP master port access by the PRU. CT_CFG.SYSCFG_bit.STANDBY_INIT = 0; } - -void SystemOnChipTeardown(void) { -} diff --git a/lib/soc/am335x/soc.h b/lib/soc/am335x/soc.h index 0734575..0e456a1 100644 --- a/lib/soc/am335x/soc.h +++ b/lib/soc/am335x/soc.h @@ -14,14 +14,9 @@ extern "C" { // Defined in delay.s. extern void SystemOnChipDelay(int cycles); -// This macro assumes standard linker commands, i.e., normal -// assignment of the PRU_DMEM_0_1 section to pru0 (0x0000...0x2000) and -// assignment of the PRU_DMEM_1_0 section to pru1 (0x2000...0x4000). -// TODO this should be compile-time. -#define PRU_CORE_NUMBER() (((&__dummy) < (void *)0x2000) ? 0 : 1) - -// Dummy variable for PRU_CORE_NUMBER check. -extern void *__dummy; +inline int SystemOnChipIsShutdown(void) { + return 0; +} #ifdef __cplusplus } diff --git a/lib/soc/soc-defs.h b/lib/soc/soc-defs.h index 6eb314c..135e969 100644 --- a/lib/soc/soc-defs.h +++ b/lib/soc/soc-defs.h @@ -35,11 +35,27 @@ extern "C" { // test helpers, reset functions, etc void SystemOnChipSetup(void); -void SystemOnChipTeardown(void); +int SystemOnChipIsShutdown(void); // maps into e.g., dynamic __delay_cycles void SystemOnChipDelay(int32_t cycles); +// Timestamp is out of place. Where should it go? +typedef struct _Timestamp Timestamp; + +struct _Timestamp { + union { + volatile uint64_t NANOS; + + // Note that the order of LOW, HIGH was discovered through + // trial-and-error. TODO: on-PRU test runner. + volatile struct { + unsigned LOW : 32; + unsigned HIGH : 32; + } NANOS_bit; + }; +}; + #ifdef __cplusplus } #endif diff --git a/lib/soc/test32/BUILD b/lib/soc/test32/BUILD index 7771db6..27078b0 100644 --- a/lib/soc/test32/BUILD +++ b/lib/soc/test32/BUILD @@ -11,6 +11,7 @@ cc_library( ], deps = [ "//lib/soc:defs", + "@com_google_absl//absl/synchronization", "//tools/toolchain/am335x:incompatible", "@ti-pru-support//include", ], diff --git a/lib/soc/test32/soc.cc b/lib/soc/test32/soc.cc index 1ea84e6..8fddcd2 100644 --- a/lib/soc/test32/soc.cc +++ b/lib/soc/test32/soc.cc @@ -2,18 +2,25 @@ // SPDX-License-Identifier: MIT #include "lib/soc/test32/soc.h" +#include "absl/synchronization/mutex.h" -soc_test32 *__soc; +absl::Mutex __system_lock; +int __system_enabled; void SystemOnChipSetup() { - __soc = (soc_test32 *)calloc(1, sizeof(soc_test32)); + absl::MutexLock lock(&__system_lock); + __system_enabled = 1; } -void SystemOnChipTeardown() { - free(__soc); - __soc = NULL; +void SystemOnChipDelay(int32_t cycles) { } -void SystemOnChipDelay(int32_t cycles) { - // TODO noop? +int SystemOnChipIsShutdown(void) { + absl::MutexLock lock(&__system_lock); + return !__system_enabled; +} + +void SystemOnChipShutdown(void) { + absl::MutexLock lock(&__system_lock); + __system_enabled = 0; } diff --git a/lib/soc/test32/soc.h b/lib/soc/test32/soc.h index 2f8113f..c4a2a3d 100644 --- a/lib/soc/test32/soc.h +++ b/lib/soc/test32/soc.h @@ -12,13 +12,7 @@ extern "C" { #endif -struct soc_test32 { - int32_t gpio_banks[GPIO_NUM_REGISTERS]; -}; - -typedef struct soc_test32 soc_test32; - -extern soc_test32 *__soc; +void SystemOnChipShutdown(void); #ifdef __cplusplus } diff --git a/lib/sync/sync.c b/lib/sync/sync.c index 3bb55b9..55e93ca 100644 --- a/lib/sync/sync.c +++ b/lib/sync/sync.c @@ -4,7 +4,6 @@ #include "sync.h" void LockInit(LockWord *word) { - // word->value = 0; ThreadListInit(&word->waiters); } diff --git a/lib/thread/thread.h b/lib/thread/thread.h index 274d512..9c528d9 100644 --- a/lib/thread/thread.h +++ b/lib/thread/thread.h @@ -49,6 +49,7 @@ struct _Thread { const char *name; int32_t stack_size; ThreadState state; + Timestamp when; union { jmp_buf run_jump; diff --git a/lib/time/BUILD b/lib/time/BUILD deleted file mode 100644 index 071cdd3..0000000 --- a/lib/time/BUILD +++ /dev/null @@ -1,29 +0,0 @@ -# -*- Mode: Python -*- -package(default_visibility = ["//visibility:public"]) - -cc_library( - name = "defs", - hdrs = [ - "time-defs.h", - ], - deps = [ - "//lib/soc", - ], -) - -cc_library( - name = "time", - srcs = [ - "time.c", - ], - hdrs = [ - "time.h", - ], - deps = [ - ":defs", - "//lib/coroutine", - ] + select({ - "//tools/toolchain:am335x": ["//lib/time/am335x"], - "//conditions:default": ["//lib/time/test32"], - }), -) diff --git a/lib/time/am335x/BUILD b/lib/time/am335x/BUILD deleted file mode 100644 index a022991..0000000 --- a/lib/time/am335x/BUILD +++ /dev/null @@ -1,12 +0,0 @@ -# -*- Mode: Python -*- -package(default_visibility = ["//visibility:public"]) - -cc_library( - name = "am335x", - hdrs = [ - "time.h", - ], - deps = [ - "//lib/time:defs", - ], -) diff --git a/lib/time/am335x/time.c b/lib/time/am335x/time.c deleted file mode 100644 index ae6bfd4..0000000 --- a/lib/time/am335x/time.c +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright Joshua MacDonald -// SPDX-License-Identifier: MIT - -#include "external/ti-pru-support/include/am335x/pru_ctrl.h" - -#define PRU_CONTROL() (PRU_CORE_NUMBER() == 0 ? PRU0_CTRL : PRU1_CTRL) - -uint32_t RawCycleCounter() { - return PRU_CONTROL().CYCLE_bit.CYCLE; -} diff --git a/lib/time/clock/BUILD b/lib/time/clock/BUILD new file mode 100644 index 0000000..066b1ce --- /dev/null +++ b/lib/time/clock/BUILD @@ -0,0 +1,42 @@ +# -*- Mode: Python -*- +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "defs", + hdrs = [ + "clock-defs.h", + ], + deps = [ + "//lib/soc", + ], +) + +cc_library( + name = "clock", + srcs = [ + "clock.c", + ], + hdrs = [ + "clock.h", + ], + deps = [ + ":defs", + ] + select({ + "//tools/toolchain:am335x": ["//lib/time/clock/am335x"], + "//conditions:default": ["//lib/time/clock/test32"], + }), +) + +cc_library( + name = "process", + srcs = [ + "process.c", + ], + hdrs = [ + "process.h", + ], + deps = [ + ":clock", + "//lib/coroutine", + ], +) diff --git a/lib/time/clock/am335x/BUILD b/lib/time/clock/am335x/BUILD new file mode 100644 index 0000000..bd2384d --- /dev/null +++ b/lib/time/clock/am335x/BUILD @@ -0,0 +1,17 @@ +# -*- Mode: Python -*- +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "am335x", + hdrs = [ + "clock-am335x.h", + ], + srcs = [ + "clock-am335x.c", + ], + deps = [ + "//lib/thread", + "//lib/time/clock:defs", + "//tools/toolchain/am335x", + ], +) diff --git a/lib/time/clock/am335x/clock-am335x.c b/lib/time/clock/am335x/clock-am335x.c new file mode 100644 index 0000000..82ccd5e --- /dev/null +++ b/lib/time/clock/am335x/clock-am335x.c @@ -0,0 +1,31 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#include + +#include "external/ti-pru-support/include/am335x/pru_iep.h" +#include "lib/time/clock/clock-defs.h" + +Timestamp __clock; + +void TimeInit(void) { + __clock.NANOS_bit.HIGH = 0; + __clock.NANOS_bit.LOW = 0; + + // The hardware reset state is for DEFAULT_INC is 5, which makes the + // IEP counter on this device a nanosecond counter, i.e., (1000 / PRU_MHZ). + // CT_IEP.TMR_GLB_CFG_bit.DEFAULT_INC = 5; + CT_IEP.TMR_GLB_CFG_bit.CNT_EN = 1; +} + +// Device-Specific PRU Read Latency Values Appendix A.1 says 12 cycles +// to read IEP_TIMER. + +void ReadClock(Timestamp *clock) { + uint32_t ts = CT_IEP.TMR_CNT; + if (ts < __clock.NANOS_bit.LOW) { + __clock.NANOS_bit.HIGH++; + } + __clock.NANOS_bit.LOW = ts; + *clock = __clock; +} diff --git a/lib/time/am335x/time.h b/lib/time/clock/am335x/clock-am335x.h similarity index 73% rename from lib/time/am335x/time.h rename to lib/time/clock/am335x/clock-am335x.h index 7120d01..934fc47 100644 --- a/lib/time/am335x/time.h +++ b/lib/time/clock/am335x/clock-am335x.h @@ -4,15 +4,13 @@ #ifndef LIB_TIME_AM335X_TIME_H #define LIB_TIME_AM335X_TIME_H -#include "lib/time/time-defs.h" +#include "lib/time/clock/clock-defs.h" #ifdef __cplusplus extern "C" { #endif -#define PRU_MHZ 2e8 - -uint32_t RawCycleCounter(void); +extern Timestamp __clock; #ifdef __cplusplus } diff --git a/lib/time/clock/clock-defs.h b/lib/time/clock/clock-defs.h new file mode 100644 index 0000000..26e39cb --- /dev/null +++ b/lib/time/clock/clock-defs.h @@ -0,0 +1,27 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#ifndef LIB_TIME_TIME_DEFS_H +#define LIB_TIME_TIME_DEFS_H + +#include "lib/soc/soc.h" +#include "lib/thread/thread.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Called by ClockInit(). +void TimeInit(void); + +// Read the clock. +void ReadClock(Timestamp *ts); + +// Sleepers, used by clock process. +extern ThreadList __asleep; + +#ifdef __cplusplus +} +#endif + +#endif // LIB_TIME_TIME_DEFS_H diff --git a/lib/time/clock/clock.c b/lib/time/clock/clock.c new file mode 100644 index 0000000..78af380 --- /dev/null +++ b/lib/time/clock/clock.c @@ -0,0 +1,26 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#include "lib/time/clock/clock.h" +#include "lib/thread/thread.h" + +#include + +// Note: I tested an implementation based on a heap, was about 500 +// bytes larger. + +ThreadList __asleep; + +void Sleep(uint32_t d) { + Thread *self = __system_current; + + ReadClock(&self->when); + TimeAdd(&self->when, d); + + ThreadListPushBack(&__asleep, self); + YieldBlocked(); +} + +void TimeAdd(Timestamp *clock, uint32_t dur) { + clock->NANOS += dur; +} diff --git a/lib/time/time.h b/lib/time/clock/clock.h similarity index 58% rename from lib/time/time.h rename to lib/time/clock/clock.h index 8cc5003..bf00cf6 100644 --- a/lib/time/time.h +++ b/lib/time/clock/clock.h @@ -10,17 +10,17 @@ extern "C" { #endif -#include "lib/time/time-defs.h" +#include "lib/time/clock/clock-defs.h" #if defined(SUPRUGLUE_AM335X) -#include "lib/time/am335x/time.h" +#include "lib/time/clock/am335x/clock-am335x.h" #elif defined(SUPRUGLUE_TEST32) -#include "lib/time/test32/time.h" +#include "lib/time/clock/test32/clock-test32.h" #endif -int Sleep(duration_t d); +void Sleep(uint32_t nanos); -int TimeInit(void); +void TimeAdd(Timestamp *clock, uint32_t nanos); #ifdef __cplusplus } diff --git a/lib/time/clock/process.c b/lib/time/clock/process.c new file mode 100644 index 0000000..c718239 --- /dev/null +++ b/lib/time/clock/process.c @@ -0,0 +1,42 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#include "process.h" +#include "clock.h" +#include "lib/coroutine/coroutine.h" + +SUPRUGLUE_DEFINE_THREAD(clockproc, 256); + +void clockProcess(ThreadID thid, Args args) { + while (1) { + Timestamp clk; + ReadClock(&clk); + + ThreadList *p = __asleep.next; + while (p != &__asleep) { + Thread *th = ThreadListEntry(p); + + int runnable = clk.NANOS >= th->when.NANOS; + if (runnable) { + ThreadListRemove(th); + } + p = p->next; + if (runnable) { + ThreadListPushBack(&__system_runnable, th); + } + } + + Yield(); + } +} + +// ClockInit enables a handler to maintain the clock. +int ClockInit(void) { + TimeInit(); + + ThreadListInit(&__asleep); + + Args args; + args.ptr = ""; + return Create(&clockproc.thread, clockProcess, args, "clock", sizeof(clockproc.space)); +} diff --git a/lib/time/clock/process.h b/lib/time/clock/process.h new file mode 100644 index 0000000..1d96092 --- /dev/null +++ b/lib/time/clock/process.h @@ -0,0 +1,17 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#ifndef LIB_TIME_CLOCK_PROCESS_H +#define LIB_TIME_CLOCK_PROCESS_H + +#ifdef __cplusplus +extern "C" { +#endif + +int ClockInit(void); + +#ifdef __cplusplus +} +#endif + +#endif // LIB_TIME_CLOCK_PROCESS_H diff --git a/lib/time/clock/test32/BUILD b/lib/time/clock/test32/BUILD new file mode 100644 index 0000000..20017a6 --- /dev/null +++ b/lib/time/clock/test32/BUILD @@ -0,0 +1,29 @@ +# -*- Mode: Python -*- +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "test32", + srcs = [ + "clock-test32.cc", + ], + hdrs = [ + "clock-test32.h", + ], + deps = [ + "//lib/thread", + "//lib/time/clock:defs", + ], +) + +cc_test( + name = "clock_test", + srcs = ["clock_test.cc"], + deps = [ + "//lib/time/clock", + "//lib/log/fmt", + "//lib/log/daemon", + "//lib/rpmsg/test32", + "@com_google_absl//absl/log", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/lib/time/clock/test32/clock-test32.cc b/lib/time/clock/test32/clock-test32.cc new file mode 100644 index 0000000..edf49d4 --- /dev/null +++ b/lib/time/clock/test32/clock-test32.cc @@ -0,0 +1,18 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#include "lib/time/clock/clock-defs.h" +#include + +using std::chrono::duration_cast; +using std::chrono::high_resolution_clock; +using std::chrono::nanoseconds; + +void TimeInit(void) { +} + +void ReadClock(Timestamp *ts) { + auto now = high_resolution_clock::now(); + + ts->NANOS = duration_cast(now.time_since_epoch()).count(); +} diff --git a/lib/time/test32/time.h b/lib/time/clock/test32/clock-test32.h similarity index 79% rename from lib/time/test32/time.h rename to lib/time/clock/test32/clock-test32.h index df22904..61b133b 100644 --- a/lib/time/test32/time.h +++ b/lib/time/clock/test32/clock-test32.h @@ -8,9 +8,7 @@ extern "C" { #endif -#include "lib/time/time-defs.h" - -#define PRU_MHZ 2e8 // @@@ +#include "lib/time/clock/clock-defs.h" #ifdef __cplusplus } diff --git a/lib/time/clock/test32/clock_test.cc b/lib/time/clock/test32/clock_test.cc new file mode 100644 index 0000000..0ce3740 --- /dev/null +++ b/lib/time/clock/test32/clock_test.cc @@ -0,0 +1,71 @@ +// Copyright Joshua MacDonald +// SPDX-License-Identifier: MIT + +#include "absl/log/log.h" +#include "absl/strings/str_format.h" +#include "lib/coroutine/coroutine.h" +#include "lib/log/daemon/daemon.h" +#include "lib/log/fmt/fmt.h" +#include "lib/rpmsg/rpmsg.h" +#include "lib/time/clock/clock.h" +#include "gtest/gtest.h" + +#include +#include + +void test_write_func(ThreadID tid, Args args) { + int32_t cnt = Atoi(args.ptr); + for (int32_t i = 0; i < cnt; i++) { + PRULOG_2U(INFO_BLOCK, "write %u", i, 0); // Logs always yield + Sleep(10); + } +} + +SUPRUGLUE_DEFINE_THREAD(writer, 500); +SUPRUGLUE_DEFINE_THREAD(syslog, 500); + +TEST(ClockTest, SleepWake) { + auto tt = NewTestTransport(); + + EXPECT_EQ(0, Init(NewSystemConfig())); + + EXPECT_EQ(0, SystemOnChipIsShutdown()); + + ClockInit(); + + EXPECT_EQ(0, Create(&writer.thread, test_write_func, Args{.ptr = "100"}, "writer", sizeof(writer.space))); + EXPECT_EQ(0, Create(&syslog.thread, SyslogProcess, Args{.ptr = ""}, "syslog", sizeof(syslog.space))); + + std::unordered_set res; + std::unordered_set expect; + + for (int i = 0; i < 100; i++) { + expect.insert(absl::StrFormat("[writer] write %u", i)); + } + + int howmany = 0; + + std::thread client([tt, &res, &howmany] { + // read until we receive the correct number, w/o overflow + for (int got = 0; got < 100;) { + Entry entry; + uint16_t blen = sizeof(entry); + EXPECT_EQ(0, HostRecv(tt, &entry, &blen)); + EXPECT_EQ(blen, sizeof(entry)); + howmany++; + EXPECT_NE(overflowMessage, entry.msg); + res.insert(Format(&entry)); + got += 1; + } + SystemOnChipShutdown(); + }); + + EXPECT_EQ(0, ::Run()); + + client.join(); + + // Make sure the logs we received were all expected + for (auto arg : res) { + EXPECT_NE(expect.end(), expect.find(arg)); + } +} diff --git a/lib/time/test32/BUILD b/lib/time/test32/BUILD deleted file mode 100644 index 77b7243..0000000 --- a/lib/time/test32/BUILD +++ /dev/null @@ -1,25 +0,0 @@ -# -*- Mode: Python -*- -package(default_visibility = ["//visibility:public"]) - -cc_library( - name = "test32", - srcs = [ - "time.cc", - ], - hdrs = [ - "time.h", - ], - deps = [ - "//lib/thread", - "//lib/time:defs", - ], -) - -cc_test( - name = "time_test", - srcs = ["time_test.cc"], - deps = [ - "//lib/time", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/lib/time/test32/test32