libn64/io: Restructure the PI thread.
authorTyler J. Stachecki <stachecki.tyler@gmail.com>
Tue, 19 Dec 2017 01:37:54 +0000 (20:37 -0500)
committerTyler J. Stachecki <stachecki.tyler@gmail.com>
Tue, 19 Dec 2017 01:37:54 +0000 (20:37 -0500)
Signed-off-by: Tyler J. Stachecki <stachecki.tyler@gmail.com>
helloworld/src/main.c
libn64/Makefile
libn64/include/io.h
libn64/io/init.c
libn64/io/pi_thread.c [new file with mode: 0644]
libn64/io/thread.c [deleted file]
libn64/os/asm/syscall.s
libn64/priv_include/io/pi_thread.h [new file with mode: 0644]
libn64/priv_include/io/thread.h [deleted file]

index 69d181d..848ac95 100644 (file)
@@ -43,13 +43,13 @@ void main(void *unused __attribute__((unused))) {
   // Below is an example of how to load the "Hello, world" resource off
   // the cart by submitting an I/O request and blocking until completion.
   struct libn64_mq *mq = libn64_mq_create();
-  struct libn64_io_request *req = (struct libn64_io_request *)
+  struct libn64_pi_request *req = (struct libn64_pi_request *)
       libn64_mq_alloc();
 
-  libn64_io_pack_request(req, mq, 0x100000, // @ 1MB
+  libn64_pi_pack_request(req, mq, 0x100000, // @ 1MB
       CART_OFFS_DATA_TXT, CART_SIZE_DATA_TXT);
 
-  libn64_io_submit(LIBN64_IO_CMD_CART2RAM, req);
+  libn64_pi_submit(LIBN64_PI_CMD_FILESYSTEM_LOAD, req);
   libn64_recv_message(mq, LIBN64_BLOCK);
 
   libn64_mq_free(req);
index e4b570d..13c65b3 100644 (file)
@@ -37,7 +37,7 @@ ASMFILES = $(call FIXPATH,\
 
 CFILES = $(call FIXPATH,\
        io/init.c \
-       io/thread.c \
+       io/pi_thread.c \
        os/fbtext.c \
        os/main.c \
        os/mm.c \
index 56e6770..b0cace6 100644 (file)
 #include <mq.h>
 #include <syscall.h>
 
-enum libn64_io_command {
-  LIBN64_IO_CMD_CART2RAM = 1,
-  LIBN64_IO_RCP_INTERRUPT = -3,
-  LIBN64_IO_CMD_INVALID = -1,
+enum libn64_pi_command {
+  LIBN64_PI_RCP_INTERRUPT = -3,
+  LIBN64_PI_CMD_FILESYSTEM_LOAD = 1,
+  LIBN64_PI_CMD_INVALID = -1,
 };
 
 enum libn64_io_response {
@@ -26,7 +26,7 @@ enum libn64_io_response {
   LIBN64_IO_RESP_ERROR = -1,
 };
 
-struct libn64_io_request {
+struct libn64_pi_request {
   uint32_t dest_address;
   uint32_t src_address;
   uint32_t size;
@@ -35,8 +35,8 @@ struct libn64_io_request {
 };
 
 libn64func
-static inline libn64_thread libn64_io_get_thread(void) {
-  libn64_thread io_thread;
+static inline libn64_thread libn64_pi_get_thread(void) {
+  libn64_thread pi_thread;
 
   __asm__ __volatile__(
     ".set noat\n\t"
@@ -46,14 +46,14 @@ static inline libn64_thread libn64_io_get_thread(void) {
     ".set gp=default\n\t"
     ".set at\n\t"
 
-    : "=r" (io_thread)
+    : "=r" (pi_thread)
   );
 
-  return io_thread;
+  return pi_thread;
 }
 
 libn64func
-static inline void libn64_io_pack_request(struct libn64_io_request *req,
+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) {
   req->dest_address = dest_address;
@@ -63,10 +63,10 @@ static inline void libn64_io_pack_request(struct libn64_io_request *req,
 }
 
 libn64func
-static inline void libn64_io_submit(uint32_t command,
-    struct libn64_io_request *request) {
-  libn64_thread io_thread = libn64_io_get_thread();
-  libn64_sendt_message1(io_thread, command, request);
+static inline void libn64_pi_submit(uint32_t command,
+    struct libn64_pi_request *request) {
+  libn64_thread pi_thread = libn64_pi_get_thread();
+  libn64_sendt_message1(pi_thread, command, request);
 }
 
 #endif
index 995e7af..771652d 100644 (file)
@@ -8,16 +8,16 @@
 // 'LICENSE', which is part of this source code package.
 //
 
-#include <io/thread.h>
+#include <io/pi_thread.h>
 #include <libn64.h>
 #include <stddef.h>
 #include <syscall.h>
 
 libn64func
 void libn64_io_init(void) {
-  libn64_thread io_thread;
+  libn64_thread pi_thread;
 
-  io_thread = libn64_thread_create(libn64_io_thread, NULL,
+  pi_thread = libn64_thread_create(libn64_pi_thread, NULL,
       LIBN64_THREAD_MAX_PRIORITY);
 
   // Store the thread address in the global block.
@@ -29,7 +29,7 @@ void libn64_io_init(void) {
     ".set gp=default\n\t"
     ".set at\n\t"
 
-    :: "r" (io_thread)
+    :: "r" (pi_thread)
     : "memory"
   );
 }
diff --git a/libn64/io/pi_thread.c b/libn64/io/pi_thread.c
new file mode 100644 (file)
index 0000000..96eb5e6
--- /dev/null
@@ -0,0 +1,119 @@
+//
+// libn64/io/pi_thread.c: Parallel interface (PI) 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/pi_thread.h>
+#include <libn64.h>
+#include <mq.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <syscall.h>
+
+libn64func
+static void filesystem_load(const struct libn64_pi_request *pi_req);
+
+libn64func
+static void libn64_pi_issue(struct libn64_mq *pi_backlog,
+    uint32_t command, const struct libn64_pi_request *pi_req);
+
+// Issues a request to the PI subsystem to load a file.
+void filesystem_load(const struct libn64_pi_request *pi_req) {
+  uint32_t pi_addr;
+
+  extern char _binary_filesystem_bin_start;
+  static const char *fs_ptr = &_binary_filesystem_bin_start;
+  uint32_t fs_offs;
+
+  // PI transfer lengths must be an even number of bytes.
+  // The source address must also be 2-byte aligned, but the
+  // filesystem packer takes care of doing that for us.
+  uint32_t transfer_size = (pi_req->size + 1) & ~0x1;
+
+  // Cart domain is 0x1000_0000, a 0x1000 header is stapled onto
+  // the cart by checksum, and the cart gets loaded to 0x8000_0400.
+  // Do a bit of fudging to figure out where the data is located.
+  __builtin_memcpy(&fs_offs, &fs_ptr, sizeof(fs_offs));
+  fs_offs -= 0x70000400;
+
+  __asm__ __volatile__(
+    ".set noreorder\n\t"
+
+    "lui %0, 0xA460\n\t"
+    "sw %1, 0x0(%0)\n\t"
+    "sw %2, 0x4(%0)\n\t"
+    "sw %3, 0xC(%0)\n\t"
+
+    ".set reorder\n\t"
+
+    : "=&r" (pi_addr)
+    : "r" (pi_req->dest_address),
+      "r" (pi_req->src_address + fs_offs),
+      "r" (transfer_size)
+  );
+}
+
+// Issues a command to the PI subsystem.
+void libn64_pi_issue(struct libn64_mq *pi_backlog,
+    uint32_t command, const struct libn64_pi_request *pi_req) {
+  void *opaque = NULL;
+
+  do {
+    switch (command) {
+      case LIBN64_PI_CMD_FILESYSTEM_LOAD:
+        filesystem_load(pi_req);
+        return;
+
+      default:
+        libn64_send_message1(pi_req->mq, LIBN64_IO_RESP_ERROR, opaque);
+        command = libn64_recv_message1(pi_backlog, LIBN64_NOBLOCK, &opaque);
+        pi_req = (struct libn64_pi_request *) opaque;
+        break;
+    }
+  } while (pi_req != NULL);
+}
+
+// Thread responsible for processing I/O requests.
+void libn64_pi_thread(void *opaque) {
+  struct libn64_mq *pi_backlog = libn64_mq_create();
+  struct libn64_pi_request *pi_req = NULL;
+
+  // This thread uses PI interrupts to watch for command completion.
+  libn64_thread_reg_intr(libn64_thread_self(), LIBN64_INTERRUPT_PI);
+
+  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_PI_RCP_INTERRUPT) {
+      if (pi_req != NULL) {
+        libn64_send_message1(pi_req->mq, LIBN64_IO_RESP_OK, pi_req);
+        command = libn64_recv_message1(pi_backlog, LIBN64_NOBLOCK, &opaque);
+
+        if ((pi_req = (struct libn64_pi_request *) opaque) != NULL)
+          libn64_pi_issue(pi_backlog, command, pi_req);
+      }
+    }
+
+    // A new command arrived; queue it up or issue it.
+    else {
+      if (pi_req != NULL) {
+        libn64_send_message1(pi_backlog, command, opaque);
+        continue;
+      }
+
+      else {
+        pi_req = (struct libn64_pi_request *) opaque;
+        libn64_pi_issue(pi_backlog, command, pi_req);
+      }
+    }
+  }
+}
+
diff --git a/libn64/io/thread.c b/libn64/io/thread.c
deleted file mode 100644 (file)
index 76a3e12..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// libn64/io/thread.c: Parallel and serial 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/thread.h>
-#include <libn64.h>
-#include <mq.h>
-#include <stdint.h>
-#include <syscall.h>
-
-libn64func
-static void libn64_io_issue(const struct libn64_io_request *req);
-
-// Issues a request to the PI subsystem.
-void libn64_io_issue(const struct libn64_io_request *req) {
-  uint32_t pi_addr;
-
-  extern char _binary_filesystem_bin_start;
-  char *fs_ptr = &_binary_filesystem_bin_start;
-  uint32_t fs_offs = (uint32_t) fs_ptr - 0x70000400;
-
-  __asm__ __volatile__(
-    ".set noreorder\n\t"
-
-    "lui %0, 0xA460\n\t"
-    "sw %1, 0x0(%0)\n\t"
-    "sw %2, 0x4(%0)\n\t"
-    "sw %3, 0xC(%0)\n\t"
-
-    ".set reorder\n\t"
-
-    : "=&r" (pi_addr)
-    : "r" (req->dest_address),
-      "r" (req->src_address + fs_offs),
-      "r" (req->size)
-  );
-}
-
-// Thread responsible for processing I/O requests.
-void libn64_io_thread(void *opaque) {
-  libn64_thread_reg_intr(libn64_thread_self(), LIBN64_INTERRUPT_PI);
-
-  struct libn64_mq *backlog = libn64_mq_create();
-  struct libn64_io_request *req = NULL;
-  int pending = 0;
-
-  while (1) {
-    uint32_t command = libn64_recvt_message1(&opaque);
-
-    switch (command) {
-      case LIBN64_IO_RCP_INTERRUPT:
-
-        // RCP signaled an interrupt for the completion of the request.
-        // Notify the requestor of the commpletion. If the backlog is
-        // not empty, issue the next request to the PI subsystem.
-        if (req != NULL) {
-          libn64_send_message1(req->mq, LIBN64_IO_RESP_OK, req);
-
-          if (pending) {
-            pending--;
-
-            libn64_recv_message1(backlog, LIBN64_BLOCK, &opaque);
-            req = (struct libn64_io_request *) opaque;
-            libn64_io_issue(req);
-          } else {
-            req = NULL;
-          }
-        }
-
-        break;
-
-      case LIBN64_IO_CMD_CART2RAM:
-
-        // If a request is already in progress, add it to the backlog.
-        // Otherwise, begin processing the request immediately.
-        if (pending) {
-          libn64_send_message1(backlog, command, req);
-          pending++;
-        } else {
-          req = (struct libn64_io_request *) opaque;
-          libn64_io_issue(req);
-        }
-
-        break;
-
-      default:
-        continue;
-    }
-  }
-}
-
index f90d00a..a069ccc 100644 (file)
@@ -512,6 +512,7 @@ libn64_recv_maybe_block_thread:
   bgezl $a1, libn64_recv_block_thread
   lw $k1, 0x8($a0)
   lui $v0, 0x8000
+  xor $at, $at, $at
   eret
 
 libn64_recv_block_thread:
diff --git a/libn64/priv_include/io/pi_thread.h b/libn64/priv_include/io/pi_thread.h
new file mode 100644 (file)
index 0000000..0d4843e
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// libn64/priv_include/io/pi_thread.h: Parallel interface (PI) 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_PI_THREAD_H
+#define LIBN64_PRIV_INCLUDE_IO_PI_THREAD_H
+
+#include <libn64.h>
+
+libn64func
+void libn64_pi_thread(void *opaque);
+
+#endif
+
diff --git a/libn64/priv_include/io/thread.h b/libn64/priv_include/io/thread.h
deleted file mode 100644 (file)
index 2b18d82..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-//
-// libn64/priv_include/io/thread.h: Parallel and serial 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_THREAD_H
-#define LIBN64_PRIV_INCLUDE_IO_THREAD_H
-
-#include <libn64.h>
-
-libn64func
-void libn64_io_thread(void *opaque);
-
-#endif
-