libn64: Add an init ucode and execute it at boot.
authorTyler J. Stachecki <stachecki.tyler@gmail.com>
Tue, 19 Dec 2017 17:21:11 +0000 (12:21 -0500)
committerTyler J. Stachecki <stachecki.tyler@gmail.com>
Tue, 19 Dec 2017 17:22:17 +0000 (12:22 -0500)
Signed-off-by: Tyler J. Stachecki <stachecki.tyler@gmail.com>
libn64/Makefile
libn64/include/rcp/rsp.h [deleted file]
libn64/include/rcp/sp.h [new file with mode: 0644]
libn64/os/main.c
libn64/priv_include/io/init.h
libn64/priv_include/sp/init.h [new file with mode: 0644]
libn64/sp/init.c [new file with mode: 0644]
libn64/ucodes/defs.h [new file with mode: 0644]
libn64/ucodes/init.rsp [new file with mode: 0644]
libn64/ucodes/init.rsps [new file with mode: 0644]
rspasm/main.c

index 13c65b3..81b2f33 100644 (file)
@@ -19,6 +19,9 @@ endif
 AS = $(call FIXPATH,$(CURDIR)/../tools/bin/mips64-elf-as)
 AR = $(call FIXPATH,$(CURDIR)/../tools/bin/mips64-elf-gcc-ar)
 CC = $(call FIXPATH,$(CURDIR)/../tools/bin/mips64-elf-gcc)
+CPP = $(call FIXPATH,$(CURDIR)/../tools/bin/mips64-elf-cpp)
+
+RSPASM = $(call FIXPATH,$(CURDIR)/../tools/bin/rspasm)
 
 CFLAGS = -Wall -Wextra -pedantic -std=c99 -I. -Iinclude -Ipriv_include
 OPTFLAGS = -Os -march=vr4300 -mtune=vr4300 -mabi=eabi -mgp32 -mlong32 \
@@ -45,11 +48,17 @@ CFILES = $(call FIXPATH,\
        os/thread.c \
        os/time.c \
        rcp/vi.c \
+       sp/init.c \
+)
+
+UCODES = $(call FIXPATH,\
+       ucodes/init.rsp \
 )
 
 OBJFILES = \
        $(CFILES:.c=.o) \
-       $(ASMFILES:.s=.o)
+       $(ASMFILES:.s=.o) \
+       $(UCODES:.rsp=.o)
 
 DEPFILES = $(OBJFILES:.o=.d)
 
@@ -71,6 +80,11 @@ libn64.a: $(OBJFILES)
        @echo $(call FIXPATH,"Compiling: libn64/$<")
        @$(CC) $(CFLAGS) $(OPTFLAGS) -MMD -c $< -o $@
 
+%.o: %.rsp %.rsps
+       @echo $(call FIXPATH,"Assembling: $(ROM_NAME)/$@")
+       @$(CPP) -E -Iucodes $< | $(RSPASM) -o $(<:.rsp=.bin) -
+       @$(CC) -x assembler-with-cpp $(CFLAGS) $(OPTFLAGS) -MMD -c $(<:.rsp=.rsps) -o $@
+
 #
 # Clean project target.
 #
diff --git a/libn64/include/rcp/rsp.h b/libn64/include/rcp/rsp.h
deleted file mode 100644 (file)
index 45388d4..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-//
-// libn64/include/rcp/rsp.h: RSP helper functions.
-//
-// 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_RCP_RSP_H
-#define LIBN64_INCLUDE_RCP_RSP_H
-
-#include <libn64.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#define RSP_STATUS_CLEAR_HALT               (1 <<  0)
-#define RSP_STATUS_SET_HALT                 (1 <<  1)
-#define RSP_STATUS_CLEAR_BROKE              (1 <<  2)
-#define RSP_STATUS_CLEAR_INTR               (1 <<  3)
-#define RSP_STATUS_SET_INTR                 (1 <<  4)
-#define RSP_STATUS_CLEAR_SSTEP              (1 <<  5)
-#define RSP_STATUS_SET_SSTEP                (1 <<  6)
-#define RSP_STATUS_CLEAR_INTR_ON_BREAK      (1 <<  7)
-#define RSP_STATUS_SET_INTR_ON_BREAK        (1 <<  8)
-#define RSP_STATUS_CLEAR_SIGNAL_0           (1 <<  9)
-#define RSP_STATUS_SET_SIGNAL_0             (1 << 10)
-#define RSP_STATUS_CLEAR_SIGNAL_1           (1 << 11)
-#define RSP_STATUS_SET_SIGNAL_1             (1 << 12)
-#define RSP_STATUS_CLEAR_SIGNAL_2           (1 << 13)
-#define RSP_STATUS_SET_SIGNAL_2             (1 << 14)
-#define RSP_STATUS_CLEAR_SIGNAL_3           (1 << 15)
-#define RSP_STATUS_SET_SIGNAL_3             (1 << 16)
-#define RSP_STATUS_CLEAR_SIGNAL_4           (1 << 17)
-#define RSP_STATUS_SET_SIGNAL_4             (1 << 18)
-#define RSP_STATUS_CLEAR_SIGNAL_5           (1 << 19)
-#define RSP_STATUS_SET_SIGNAL_5             (1 << 20)
-#define RSP_STATUS_CLEAR_SIGNAL_6           (1 << 21)
-#define RSP_STATUS_SET_SIGNAL_6             (1 << 22)
-#define RSP_STATUS_CLEAR_SIGNAL_7           (1 << 23)
-#define RSP_STATUS_SET_SIGNAL_7             (1 << 24)
-
-// Issues a DMA to the RSP.
-//
-// Does NOT perform any checks. Be sure that you grab the
-// semaphore as needed, adjust the length (subtract one from
-// the amount you actually want copied), etc.
-libn64func
-static inline void rsp_issue_dma_to_rsp(
-  uint32_t paddr, uint32_t sp_addr, size_t len) {
-  __asm__ __volatile__(
-    "sw %[sp_addr], 0x00(%[sp_region])\n\t"
-    "sw %[paddr],   0x04(%[sp_region])\n\t"
-    "sw %[len],     0x08(%[sp_region])\n\t"
-
-    :: [paddr] "r" (paddr), [sp_addr] "r" (sp_addr), [len] "r" (len),
-       [sp_region] "r" (0xA4040000U)
-  );
-}
-
-// Checks for a pending RSP DMA.
-//
-// Returns 1 if a DMA is pending, 0 otherwise.
-libn64func
-static inline uint32_t rsp_is_dma_pending(void) {
-  return *(volatile const uint32_t *) 0xA4040018;
-}
-
-// Sets the RSP PC register.
-libn64func
-static inline void rsp_set_pc(uint32_t pc) {
-  *(volatile uint32_t *) 0xA4080000 = pc;
-}
-
-// Updates the RSP status flags according to mask.
-//
-// (see RSP_STATUS_CLEAR_* and RSP_STATUS_SET_*)
-libn64func
-static inline void rsp_set_status(uint32_t mask) {
-  *(volatile uint32_t *) 0xA4040010 = mask;
-}
-
-#endif
-
diff --git a/libn64/include/rcp/sp.h b/libn64/include/rcp/sp.h
new file mode 100644 (file)
index 0000000..e898fe4
--- /dev/null
@@ -0,0 +1,91 @@
+//
+// libn64/include/rcp/sp.h: Signal process (SP) helper functions.
+//
+// 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_RCP_SP_H
+#define LIBN64_INCLUDE_RCP_SP_H
+
+#include <libn64.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define RSP_STATUS_CLEAR_HALT               (1 <<  0)
+#define RSP_STATUS_SET_HALT                 (1 <<  1)
+#define RSP_STATUS_CLEAR_BROKE              (1 <<  2)
+#define RSP_STATUS_CLEAR_INTR               (1 <<  3)
+#define RSP_STATUS_SET_INTR                 (1 <<  4)
+#define RSP_STATUS_CLEAR_SSTEP              (1 <<  5)
+#define RSP_STATUS_SET_SSTEP                (1 <<  6)
+#define RSP_STATUS_CLEAR_INTR_ON_BREAK      (1 <<  7)
+#define RSP_STATUS_SET_INTR_ON_BREAK        (1 <<  8)
+#define RSP_STATUS_CLEAR_SIGNAL_0           (1 <<  9)
+#define RSP_STATUS_SET_SIGNAL_0             (1 << 10)
+#define RSP_STATUS_CLEAR_SIGNAL_1           (1 << 11)
+#define RSP_STATUS_SET_SIGNAL_1             (1 << 12)
+#define RSP_STATUS_CLEAR_SIGNAL_2           (1 << 13)
+#define RSP_STATUS_SET_SIGNAL_2             (1 << 14)
+#define RSP_STATUS_CLEAR_SIGNAL_3           (1 << 15)
+#define RSP_STATUS_SET_SIGNAL_3             (1 << 16)
+#define RSP_STATUS_CLEAR_SIGNAL_4           (1 << 17)
+#define RSP_STATUS_SET_SIGNAL_4             (1 << 18)
+#define RSP_STATUS_CLEAR_SIGNAL_5           (1 << 19)
+#define RSP_STATUS_SET_SIGNAL_5             (1 << 20)
+#define RSP_STATUS_CLEAR_SIGNAL_6           (1 << 21)
+#define RSP_STATUS_SET_SIGNAL_6             (1 << 22)
+#define RSP_STATUS_CLEAR_SIGNAL_7           (1 << 23)
+#define RSP_STATUS_SET_SIGNAL_7             (1 << 24)
+
+// Issues a DMA to the RSP.
+//
+// Does NOT perform any checks. Be sure that you grab the
+// semaphore as needed, adjust the length (subtract one from
+// the amount you actually want copied), etc.
+libn64func
+static inline void libn64_rsp_dma_to_rsp(
+  uint32_t sp_addr, uint32_t paddr, size_t len) {
+  __asm__ __volatile__(
+    "sw %[sp_addr], 0x00(%[sp_region])\n\t"
+    "sw %[paddr],   0x04(%[sp_region])\n\t"
+    "sw %[len],     0x08(%[sp_region])\n\t"
+
+    :: [sp_addr] "r" (sp_addr), [paddr] "r" (paddr), [len] "r" (len),
+       [sp_region] "r" (0xA4040000U)
+  );
+}
+
+// Checks for a pending RSP DMA.
+//
+// Returns 1 if a DMA is pending, 0 otherwise.
+libn64func
+static inline uint32_t libn64_rsp_is_dma_pending(void) {
+  return *(volatile const uint32_t *) 0xA4040018;
+}
+
+// Returns the RSP status register.
+libn64func
+static inline uint32_t libn64_rsp_get_status(void) {
+  return *(volatile const uint32_t *) 0xA4040010;
+}
+
+// Sets the RSP PC register.
+libn64func
+static inline void libn64_rsp_set_pc(uint32_t pc) {
+  *(volatile uint32_t *) 0xA4080000 = pc;
+}
+
+// Updates the RSP status flags according to mask.
+//
+// (see RSP_STATUS_CLEAR_* and RSP_STATUS_SET_*)
+libn64func
+static inline void libn64_rsp_set_status(uint32_t mask) {
+  *(volatile uint32_t *) 0xA4040010 = mask;
+}
+
+#endif
+
index d505751..87d2434 100644 (file)
@@ -14,6 +14,7 @@
 #include <os/mm.h>
 #include <os/thread.h>
 #include <os/time.h>
+#include <sp/init.h>
 #include <stddef.h>
 #include <syscall.h>
 
@@ -52,8 +53,9 @@ void libn64_main(uint32_t kernel_sp, uint32_t bss_end) {
   // pages on top of our active stack, but it's fine for now...
   libn64_mm_init(kernel_sp - 4096 * 8, kernel_sp);
 
-  // Kickoff the IO engine.
+  // Kickoff the IO engine and initialize the SP.
   libn64_io_init();
+  libn64_sp_init();
 
   // This thread invokes main() and becomes the idle thread.
   libn64_idle_thread();
index e3dab8d..83bba49 100644 (file)
@@ -1,5 +1,5 @@
 //
-// libn64/priv_include/io//init.h: Parallel and serial I/O initialization.
+// libn64/priv_include/io/init.h: Parallel and serial I/O initialization.
 //
 // n64chain: A (free) open-source N64 development toolchain.
 // Copyright 2014-16 Tyler J. Stachecki <stachecki.tyler@gmail.com>
diff --git a/libn64/priv_include/sp/init.h b/libn64/priv_include/sp/init.h
new file mode 100644 (file)
index 0000000..28f1286
--- /dev/null
@@ -0,0 +1,20 @@
+//
+// libn64/priv_include/sp/init.h: Signal processor (SP) initialization.
+//
+// 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_INIT_H
+#define LIBN64_PRIV_INCLUDE_SP_INIT_H
+
+#include <libn64.h>
+
+libn64func
+void libn64_sp_init(void);
+
+#endif
+
diff --git a/libn64/sp/init.c b/libn64/sp/init.c
new file mode 100644 (file)
index 0000000..3d99489
--- /dev/null
@@ -0,0 +1,39 @@
+//
+// libn64/sp/init.c: Signal processor (SP) initialization.
+//
+// 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 <rcp/sp.h>
+#include <sp/init.h>
+
+libn64func
+void libn64_sp_init(void) {
+  extern char libn64_ucode_init;
+  static const char *ucode_ptr = &libn64_ucode_init;
+  uint32_t ucode_address;
+
+  libn64_rsp_set_status(RSP_STATUS_SET_HALT);
+  while (libn64_rsp_is_dma_pending());
+
+  // DMA the initialization ucode to the RSP and spin until its done.
+  __builtin_memcpy(&ucode_address, &ucode_ptr, sizeof(ucode_address));
+  ucode_address &= 0xFFFFFF;
+
+  libn64_rsp_dma_to_rsp(0x04000000, ucode_address + 0x0000, 0xFFF);
+  while (libn64_rsp_is_dma_pending());
+
+  libn64_rsp_dma_to_rsp(0x04001000, ucode_address + 0x1000, 0xFFF);
+  while (libn64_rsp_is_dma_pending());
+
+  // Execute the ucode and wait for it to complete.
+  libn64_rsp_set_pc(0x04001000);
+  libn64_rsp_set_status(RSP_STATUS_CLEAR_HALT | RSP_STATUS_CLEAR_BROKE);
+  while ((libn64_rsp_get_status() & 0x3) == 0x3);
+}
+
diff --git a/libn64/ucodes/defs.h b/libn64/ucodes/defs.h
new file mode 100644 (file)
index 0000000..ef85be1
--- /dev/null
@@ -0,0 +1,41 @@
+; RSP CP0 registers
+.set DMA_CACHE,             $0
+.set DMA_DRAM,              $1
+.set DMA_READ_LENGTH,       $2
+.set DMA_WRITE_LENGTH,      $3
+.set SP_STATUS,             $4
+.set DMA_FULL,              $5
+.set DMA_BUSY,              $6
+.set SP_RESERVED,           $7
+.set CMD_START,             $8
+.set CMD_END,               $9
+.set CMD_CURRENT,           $10
+.set CMD_STATUS,            $11
+.set CMD_CLOCK,             $12
+.set CMD_BUSY,              $13
+.set CMD_PIPE_BUSY,         $14
+.set CMD_TMEM_BUSY,         $15
+
+; SP_STATUS write flags
+.set CLEAR_HALT,            0x1
+.set SET_HALT,              0x2
+.set CLEAR_BROKE,           0x4
+.set CLEAR_RSP_INTERRUPT,   0x8
+.set SET_RSP_INTERRUPT,     0x10
+.set CLEAR_SINGLE_STEP,     0x20
+.set SET_SINGLE_STEP,       0x40
+.set CLEAR_INTR_ON_BREAK,   0x80
+.set SET_INTR_ON_BREAK,     0x100
+
+; CMD_STATUS write flags
+.set CLEAR_XBUS_DMEM_DMA,   0x1
+.set SET_XBUS_DMEM_DMA,     0x2
+.set CLEAR_FREEZE,          0x4
+.set SET_FREEZE,            0x8
+.set CLEAR_FLUSH,           0x10
+.set SET_FLUSH,             0x20
+.set CLEAR_TMEM_COUNTER,    0x40
+.set CLEAR_PIPE_COUNTER,    0x80
+.set CLEAR_CMD_COUNTER,     0x100
+.set CLEAR_CLOCK_COUNTER,   0x200
+
diff --git a/libn64/ucodes/init.rsp b/libn64/ucodes/init.rsp
new file mode 100644 (file)
index 0000000..c02cf29
--- /dev/null
@@ -0,0 +1,18 @@
+#include "defs.h"
+
+.text
+
+; Initialize the RSP (configure CP0, load constants, etc.)
+init_rsp:
+  addiu $at, $0, (CLEAR_RSP_INTERRUPT | SET_INTR_ON_BREAK)
+  mtc0 $at, SP_STATUS
+
+; Initialize the RDP (enable the XBUS, etc.)
+init_rdp:
+  addiu $at, $0, (SET_XBUS_DMEM_DMA | CLEAR_FREEZE | CLEAR_FLUSH)
+  mtc0 $at, CMD_STATUS
+
+; Raise an interrupt - we are done.
+  break
+  nop
+
diff --git a/libn64/ucodes/init.rsps b/libn64/ucodes/init.rsps
new file mode 100644 (file)
index 0000000..2bf7ec3
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# libn64/ucodes/init.rsps: RSP initialization ucode container.
+#
+# 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>
+
+.section .text.libn64.ucode, "ax", @progbits
+
+.global libn64_ucode_init
+.type libn64_ucode_init, @object
+.align 4
+libn64_ucode_init:
+.incbin "ucodes/init.bin"
+
+.size libn64_ucode_init,.-libn64_ucode_init
+
index becbe45..721052e 100644 (file)
@@ -88,6 +88,7 @@ int assemble(FILE *in, FILE *out) {
 }
 
 int main(int argc, const char *argv[]) {
+  const char *output_path = NULL;
   int status = EXIT_SUCCESS;
   FILE *input, *output;
   int i;
@@ -147,6 +148,7 @@ int main(int argc, const char *argv[]) {
               fprintf(stderr, "Failed to open for writing: %s.\n", argv[i + 1]);
 
               i = argc;
+              output_path = argv[i + 1];
               status = EXIT_FAILURE;
               break;
             }
@@ -184,8 +186,9 @@ int main(int argc, const char *argv[]) {
     else if (output == NULL)
       fprintf(stderr, "An output file was not specified.\n");
 
-    else
+    else {
       status = assemble(input, output);
+    }
   }
 
   if (input && input != stdin)
@@ -194,6 +197,9 @@ int main(int argc, const char *argv[]) {
   if (output && output != stdout)
     fclose(output);
 
+  if (status != EXIT_SUCCESS && output_path != NULL)
+    remove(output_path);
+
   return status;
 }