libn64: Add a thread for managing the SI.
authorTyler J. Stachecki <stachecki.tyler@gmail.com>
Sun, 11 Mar 2018 00:08:51 +0000 (19:08 -0500)
committerTyler J. Stachecki <stachecki.tyler@gmail.com>
Sun, 11 Mar 2018 00:08:51 +0000 (19:08 -0500)
Signed-off-by: Tyler J. Stachecki <stachecki.tyler@gmail.com>
libn64/Makefile
libn64/include/io.h
libn64/io/init.c
libn64/io/si_thread.c [new file with mode: 0644]
libn64/os/main.c
libn64/priv_include/io/si_thread.h [new file with mode: 0644]
threadtest/src/main.c

index ff966d7..d49012f 100644 (file)
@@ -41,6 +41,7 @@ ASMFILES = $(call FIXPATH,\
 CFILES = $(call FIXPATH,\
        io/init.c \
        io/pi_thread.c \
+       io/si_thread.c \
        os/fbtext.c \
        os/main.c \
        os/mm.c \
index b0cace6..d970e7a 100644 (file)
@@ -21,6 +21,11 @@ enum libn64_pi_command {
   LIBN64_PI_CMD_INVALID = -1,
 };
 
+enum libn64_si_command {
+  LIBN64_SI_RCP_INTERRUPT = -5,
+  LIBN64_SI_CMD_INVALID = -1,
+};
+
 enum libn64_io_response {
   LIBN64_IO_RESP_OK = 1,
   LIBN64_IO_RESP_ERROR = -1,
@@ -34,6 +39,13 @@ struct libn64_pi_request {
   struct libn64_mq *mq;
 };
 
+struct libn64_si_request {
+  uint32_t address;
+  uint32_t unused[2];
+
+  struct libn64_mq *mq;
+};
+
 libn64func
 static inline libn64_thread libn64_pi_get_thread(void) {
   libn64_thread pi_thread;
@@ -53,6 +65,24 @@ static inline libn64_thread libn64_pi_get_thread(void) {
 }
 
 libn64func
+static inline libn64_thread libn64_si_get_thread(void) {
+  libn64_thread si_thread;
+
+  __asm__ __volatile__(
+    ".set noat\n\t"
+    ".set gp=64\n\t"
+    "lui $at, 0x8000\n\t"
+    "lw %0, 0x454($at)\n\t"
+    ".set gp=default\n\t"
+    ".set at\n\t"
+
+    : "=r" (si_thread)
+  );
+
+  return si_thread;
+}
+
+libn64func
 static inline void libn64_pi_pack_request(struct libn64_pi_request *req,
     struct libn64_mq *mq, uint32_t dest_address, uint32_t src_address,
     uint32_t size) {
@@ -69,5 +99,18 @@ static inline void libn64_pi_submit(uint32_t command,
   libn64_sendt_message1(pi_thread, command, request);
 }
 
+libn64func
+static inline void libn64_si_pack_request(
+    struct libn64_si_request *req, uint32_t address) {
+  req->address = address;
+}
+
+libn64func
+static inline void libn64_si_submit(uint32_t command,
+    struct libn64_si_request *request) {
+  libn64_thread si_thread = libn64_si_get_thread();
+  libn64_sendt_message1(si_thread, command, request);
+}
+
 #endif
 
index c37bd16..9507535 100644 (file)
 
 #include <io/init.h>
 #include <io/pi_thread.h>
+#include <io/si_thread.h>
 #include <libn64.h>
 #include <stddef.h>
 #include <syscall.h>
 
 void libn64_io_init(void) {
-  libn64_thread pi_thread;
+  libn64_thread pi_thread, si_thread;
 
   pi_thread = libn64_thread_create(libn64_pi_thread, NULL,
       LIBN64_THREAD_MAX_PRIORITY);
 
+  si_thread = libn64_thread_create(libn64_si_thread, NULL,
+      LIBN64_THREAD_MAX_PRIORITY);
+
   // Store the thread address in the global block.
   __asm__ __volatile__(
     ".set noat\n\t"
     ".set gp=64\n\t"
     "lui $at, 0x8000\n\t"
     "sw %0, 0x450($at)\n\t"
+    "sw %1, 0x454($at)\n\t"
     ".set gp=default\n\t"
     ".set at\n\t"
 
-    :: "r" (pi_thread)
+    :: "r" (pi_thread), "r" (si_thread)
     : "memory"
   );
 }
diff --git a/libn64/io/si_thread.c b/libn64/io/si_thread.c
new file mode 100644 (file)
index 0000000..e6a1e69
--- /dev/null
@@ -0,0 +1,76 @@
+//
+// libn64/io/si_thread.c: Parallel interface (SI) I/O engine.
+//
+// n64chain: A (free) open-source N64 development toolchain.
+// Copyright 2014-16 Tyler J. Stachecki <stachecki.tyler@gmail.com>
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include <io.h>
+#include <io/si_thread.h>
+#include <libn64.h>
+#include <mq.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <syscall.h>
+
+libn64func
+static void libn64_si_issue(struct libn64_mq *si_backlog,
+    uint32_t command, const struct libn64_si_request *si_req);
+
+// Issues a command to the SI subsystem.
+void libn64_si_issue(struct libn64_mq *si_backlog,
+    uint32_t command, const struct libn64_si_request *si_req) {
+  void *opaque = NULL;
+
+  do {
+    switch (command) {
+      default:
+        libn64_send_message1(si_req->mq, LIBN64_IO_RESP_ERROR, opaque);
+        command = libn64_recv_message1(si_backlog, LIBN64_NOBLOCK, &opaque);
+        si_req = (struct libn64_si_request *) opaque;
+        break;
+    }
+  } while (si_req != NULL);
+}
+
+// Thread responsible for processing I/O requests.
+void libn64_si_thread(void *opaque) {
+  struct libn64_mq *si_backlog = libn64_mq_create();
+  struct libn64_si_request *si_req = NULL;
+
+  // This thread uses SI interrupts to watch for command completion.
+  libn64_thread_reg_intr(libn64_thread_self(), LIBN64_INTERRUPT_SI);
+
+  while (1) {
+    uint32_t command = libn64_recvt_message1(&opaque);
+
+    // RCP signaled an interrupt for the completion of the request.
+    // Notify the requestor of the request commpletion.
+    if ((int32_t) command == LIBN64_SI_RCP_INTERRUPT) {
+      if (si_req != NULL) {
+        libn64_send_message1(si_req->mq, LIBN64_IO_RESP_OK, si_req);
+        command = libn64_recv_message1(si_backlog, LIBN64_NOBLOCK, &opaque);
+
+        if ((si_req = (struct libn64_si_request *) opaque) != NULL)
+          libn64_si_issue(si_backlog, command, si_req);
+      }
+    }
+
+    // A new command arrived; queue it up or issue it.
+    else {
+      if (si_req != NULL) {
+        libn64_send_message1(si_backlog, command, opaque);
+        continue;
+      }
+
+      else {
+        si_req = (struct libn64_si_request *) opaque;
+        libn64_si_issue(si_backlog, command, si_req);
+      }
+    }
+  }
+}
+
index e657f9a..7852e33 100644 (file)
@@ -51,7 +51,7 @@ void libn64_main(uint32_t kernel_sp, uint32_t bss_end) {
   // The user can grow this themselves if they want more memory.
   // This is kind of "dangerous" in the sense that we allocate
   // pages on top of our active stack, but it's fine for now...
-  libn64_mm_init(kernel_sp - 4096 * 8, kernel_sp);
+  libn64_mm_init(kernel_sp - 4096 * 16, kernel_sp);
 
   // Kickoff the IO engine and initialize the SP.
   libn64_io_init();
diff --git a/libn64/priv_include/io/si_thread.h b/libn64/priv_include/io/si_thread.h
new file mode 100644 (file)
index 0000000..b7d52d5
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// libn64/priv_include/io/si_thread.h: Serial interface (SI) I/O engine.
+//
+// n64chain: A (free) open-source N64 development toolchain.
+// Copyright 2014-16 Tyler J. Stachecki <stachecki.tyler@gmail.com>
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef LIBN64_PRIV_INCLUDE_IO_SI_THREAD_H
+#define LIBN64_PRIV_INCLUDE_IO_SI_THREAD_H
+
+#include <libn64.h>
+
+libn64func
+void libn64_si_thread(void *opaque);
+
+#endif
+
index 49712fa..efedaf7 100644 (file)
@@ -144,7 +144,7 @@ void main(void *unused __attribute__((unused))) {
   libn64_thread_reg_intr(vi_thr, LIBN64_INTERRUPT_VI);
 
   // Spawn a few medium-priority box animation threads.
-  for (i = 1; i < 11; i++) {
+  for (i = 1; i < 10; i++) {
     args.vi_state = &vi_state;
     args.init_x_dir = i & 1;
     args.init_y_dir = (i >> 1) & 1;