libn64: Add a thread for managing the SP.
authorTyler J. Stachecki <stachecki.tyler@gmail.com>
Sat, 10 Mar 2018 23:33:23 +0000 (18:33 -0500)
committerTyler J. Stachecki <stachecki.tyler@gmail.com>
Sat, 10 Mar 2018 23:33:23 +0000 (18:33 -0500)
Signed-off-by: Tyler J. Stachecki <stachecki.tyler@gmail.com>
libn64/Makefile
libn64/include/sp.h [new file with mode: 0644]
libn64/io/init.c
libn64/priv_include/sp/sp_thread.h [new file with mode: 0644]
libn64/sp/init.c
libn64/sp/sp_thread.c [new file with mode: 0644]
threadtest/src/main.c

index 1b181c6..ff966d7 100644 (file)
@@ -49,6 +49,7 @@ CFILES = $(call FIXPATH,\
        os/time.c \
        rcp/vi.c \
        sp/init.c \
+       sp/sp_thread.c \
 )
 
 UCODES = $(call FIXPATH,\
diff --git a/libn64/include/sp.h b/libn64/include/sp.h
new file mode 100644 (file)
index 0000000..0d8b697
--- /dev/null
@@ -0,0 +1,72 @@
+//
+// libn64/include/sp.h: Signal processor engine interface.
+//
+// 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_INCLUDE_SP_H
+#define LIBN64_INCLUDE_SP_H
+
+#include <libn64.h>
+#include <mq.h>
+#include <syscall.h>
+
+enum libn64_sp_command {
+  LIBN64_SP_RCP_INTERRUPT = -4,
+  LIBN64_SP_CMD_INVALID = -1,
+};
+
+enum libn64_sp_response {
+  LIBN64_SP_RESP_OK = 1,
+  LIBN64_SP_RESP_ERROR = -1,
+};
+
+struct libn64_sp_request {
+  uint32_t dest_address;
+  uint32_t src_address;
+  uint32_t size;
+
+  struct libn64_mq *mq;
+};
+
+libn64func
+static inline libn64_thread libn64_sp_get_thread(void) {
+  libn64_thread sp_thread;
+
+  __asm__ __volatile__(
+    ".set noat\n\t"
+    ".set gp=64\n\t"
+    "lui $at, 0x8000\n\t"
+    "lw %0, 0x458($at)\n\t"
+    ".set gp=default\n\t"
+    ".set at\n\t"
+
+    : "=r" (sp_thread)
+  );
+
+  return sp_thread;
+}
+
+libn64func
+static inline void libn64_sp_pack_request(struct libn64_sp_request *req,
+    struct libn64_mq *mq, uint32_t dest_address, uint32_t src_address,
+    uint32_t size) {
+  req->dest_address = dest_address;
+  req->src_address = src_address;
+  req->size = size;
+  req->mq = mq;
+}
+
+libn64func
+static inline void libn64_sp_submit(uint32_t command,
+    struct libn64_sp_request *request) {
+  libn64_thread sp_thread = libn64_sp_get_thread();
+  libn64_sendt_message1(sp_thread, command, request);
+}
+
+#endif
+
index 771652d..c37bd16 100644 (file)
@@ -8,12 +8,12 @@
 // 'LICENSE', which is part of this source code package.
 //
 
+#include <io/init.h>
 #include <io/pi_thread.h>
 #include <libn64.h>
 #include <stddef.h>
 #include <syscall.h>
 
-libn64func
 void libn64_io_init(void) {
   libn64_thread pi_thread;
 
diff --git a/libn64/priv_include/sp/sp_thread.h b/libn64/priv_include/sp/sp_thread.h
new file mode 100644 (file)
index 0000000..9631a01
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// libn64/priv_include/sp/sp_thread.h: Signal proceessor (SP) 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_SP_SP_THREAD_H
+#define LIBN64_PRIV_INCLUDE_SP_SP_THREAD_H
+
+#include <libn64.h>
+
+libn64func
+void libn64_sp_thread(void *opaque);
+
+#endif
+
index 5930dd7..06989d7 100644 (file)
@@ -11,6 +11,9 @@
 #include <libn64.h>
 #include <rcp/sp.h>
 #include <sp/init.h>
+#include <sp/sp_thread.h>
+#include <stddef.h>
+#include <syscall.h>
 
 libn64func
 void libn64_sp_init(void) {
@@ -35,5 +38,24 @@ void libn64_sp_init(void) {
   libn64_rsp_set_pc(0x04001000);
   libn64_rsp_set_status(RSP_STATUS_CLEAR_HALT | RSP_STATUS_CLEAR_BROKE);
   while ((libn64_rsp_get_status() & 0x3) != 0x3);
+
+  // Start thread
+  libn64_thread sp_thread;
+
+  sp_thread = libn64_thread_create(libn64_sp_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, 0x458($at)\n\t"
+    ".set gp=default\n\t"
+    ".set at\n\t"
+
+    :: "r" (sp_thread)
+    : "memory"
+  );
 }
 
diff --git a/libn64/sp/sp_thread.c b/libn64/sp/sp_thread.c
new file mode 100644 (file)
index 0000000..e2adc9a
--- /dev/null
@@ -0,0 +1,76 @@
+//
+// libn64/sp/sp_thread.c: Signal processor (SP) 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 <libn64.h>
+#include <mq.h>
+#include <sp.h>
+#include <sp/sp_thread.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <syscall.h>
+
+libn64func
+static void libn64_sp_issue(struct libn64_mq *sp_backlog,
+    uint32_t command, const struct libn64_sp_request *sp_req);
+
+// Issues a command to the SP subsystem.
+void libn64_sp_issue(struct libn64_mq *sp_backlog,
+    uint32_t command, const struct libn64_sp_request *sp_req) {
+  void *opaque = NULL;
+
+  do {
+    switch (command) {
+      default:
+        libn64_send_message1(sp_req->mq, LIBN64_SP_RESP_ERROR, opaque);
+        command = libn64_recv_message1(sp_backlog, LIBN64_NOBLOCK, &opaque);
+        sp_req = (struct libn64_sp_request *) opaque;
+        break;
+    }
+  } while (sp_req != NULL);
+}
+
+// Thread responsible for processing SP requests/events.
+void libn64_sp_thread(void *opaque) {
+  struct libn64_mq *sp_backlog = libn64_mq_create();
+  struct libn64_sp_request *sp_req = NULL;
+
+  // This thread uses SP interrupts to watch for command completion.
+  libn64_thread_reg_intr(libn64_thread_self(), LIBN64_INTERRUPT_SP);
+
+  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_SP_RCP_INTERRUPT) {
+      if (sp_req != NULL) {
+        libn64_send_message1(sp_req->mq, LIBN64_SP_RESP_OK, sp_req);
+        command = libn64_recv_message1(sp_backlog, LIBN64_NOBLOCK, &opaque);
+
+        if ((sp_req = (struct libn64_sp_request *) opaque) != NULL)
+          libn64_sp_issue(sp_backlog, command, sp_req);
+      }
+    }
+
+    // A new command arrived; queue it up or issue it.
+    else {
+      if (sp_req != NULL) {
+        libn64_send_message1(sp_backlog, command, opaque);
+        continue;
+      }
+
+      else {
+        sp_req = (struct libn64_sp_request *) opaque;
+        libn64_sp_issue(sp_backlog, command, sp_req);
+      }
+    }
+  }
+}
+
index 91f58b6..49712fa 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 < 12; i++) {
+  for (i = 1; i < 11; i++) {
     args.vi_state = &vi_state;
     args.init_x_dir = i & 1;
     args.init_y_dir = (i >> 1) & 1;