os/time.c \
rcp/vi.c \
sp/init.c \
+ sp/sp_thread.c \
)
UCODES = $(call FIXPATH,\
--- /dev/null
+//
+// 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
+
// '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;
--- /dev/null
+//
+// 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
+
#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) {
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"
+ );
}
--- /dev/null
+//
+// 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);
+ }
+ }
+ }
+}
+
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;