From 4bd5111280c0ed6f3f0d1d49b5076fa95291f3f1 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 27 Jan 2024 11:44:08 -0500 Subject: [PATCH] [jak3] dma, dma-bucket, dma-buffer (#3331) --- decompiler/config/jak3/all-types.gc | 101 +++++--- .../config/jak3/ntsc_v1/type_casts.jsonc | 15 ++ .../config/jak3/ntsc_v1/var_names.jsonc | 30 +++ goal_src/jak3/engine/dma/dma-bucket.gc | 60 +++++ goal_src/jak3/engine/dma/dma-buffer.gc | 167 ++++++++++++ goal_src/jak3/engine/dma/dma.gc | 154 +++++++++++ goal_src/jak3/engine/gfx/hw/video-h.gc | 1 + goal_src/jak3/engine/util/profile-h.gc | 3 + .../jak3/engine/dma/dma-bucket_REF.gc | 73 ++++++ .../jak3/engine/dma/dma-buffer_REF.gc | 241 ++++++++++++++++++ .../jak3/engine/geometry/geometry_REF.gc | 6 +- test/offline/config/jak3/config.jsonc | 4 +- 12 files changed, 809 insertions(+), 46 deletions(-) create mode 100644 test/decompiler/reference/jak3/engine/dma/dma-bucket_REF.gc create mode 100644 test/decompiler/reference/jak3/engine/dma/dma-buffer_REF.gc diff --git a/decompiler/config/jak3/all-types.gc b/decompiler/config/jak3/all-types.gc index 7ab28b8e9d2..2f16c4b8235 100644 --- a/decompiler/config/jak3/all-types.gc +++ b/decompiler/config/jak3/all-types.gc @@ -4215,35 +4215,36 @@ ;; dma ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; (define-extern dma-sync-hang function) ;; (function dma-bank none) -;; (define-extern dma-sync-crash function) ;; (function dma-bank none) -;; (define-extern dma-send function) ;; (function dma-bank uint uint none) -;; (define-extern dma-send-chain function) ;; (function dma-bank-source uint none) -;; (define-extern dma-send-chain-no-tte function) ;; (function dma-bank-source uint none) -;; (define-extern dma-send-chain-no-flush function) ;; (function dma-bank-source uint none) -;; (define-extern dma-send-to-spr function) ;; (function uint uint uint symbol none) -;; (define-extern dma-send-to-spr-no-flush function) ;; (function uint uint uint symbol none) -;; (define-extern dma-send-from-spr function) ;; (function uint uint uint symbol none) -;; (define-extern dma-send-from-spr-no-flush function) ;; (function uint uint uint symbol none) -;; (define-extern dma-initialize function) ;; (function none) -;; (define-extern clear-vu0-mem function) ;; (function none) -;; (define-extern clear-vu1-mem function) ;; (function none) -;; (define-extern dump-vu1-mem function) ;; (function none) -;; (define-extern dump-vu1-range function) ;; (function uint uint symbol) -;; (define-extern reset-vif1-path function) ;; (function none) -;; (define-extern ultimate-memcpy function) ;; (function pointer pointer uint none) -;; (define-extern symlink2 function) ;; (function none) -;; (define-extern symlink3 function) ;; (function none) +(define-extern dma-sync-hang (function dma-bank none)) +(define-extern dma-sync-crash (function dma-bank none)) +(define-extern dma-send (function dma-bank uint uint none)) +(define-extern dma-send-chain (function dma-bank-source uint none)) +(define-extern dma-send-chain-no-tte (function dma-bank-source uint none)) +(define-extern dma-send-chain-no-flush (function dma-bank-source uint none)) +(define-extern dma-send-to-spr (function uint uint uint symbol none)) +(define-extern dma-send-to-spr-no-flush (function uint uint uint symbol none)) +(define-extern dma-send-from-spr (function uint uint uint symbol none)) +(define-extern dma-send-from-spr-no-flush (function uint uint uint symbol none)) +(define-extern dma-initialize (function none)) +(define-extern clear-vu0-mem (function none)) +(define-extern clear-vu1-mem (function none)) +(define-extern dump-vu1-mem (function none)) +(define-extern dump-vu1-range (function uint uint symbol)) +(define-extern reset-vif1-path (function none)) +(define-extern ultimate-memcpy (function pointer pointer uint none)) +(define-extern symlink2 (function none)) +(define-extern symlink3 (function none)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; dma-buffer ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (deftype dma-packet (structure) - ((dma dma-tag :offset-assert 0) ;; dma-tag + "The header for a DMA transfer, containing an DMA tag, and VIF tags." + ((dma dma-tag :offset-assert 0) (vif0 vif-tag :offset-assert 8) ;; guessed by decompiler (vif1 vif-tag :offset-assert 12) ;; guessed by decompiler - (quad uint128 :offset 0) + (quad uint128 :offset-assert 0 :overlay-at dma) ) :method-count-assert 9 :size-assert #x10 @@ -4251,6 +4252,7 @@ ) (deftype dma-packet-array (inline-array-class) + "Unused dma array. Unclear how it should be used." ((data dma-packet :dynamic :offset-assert 16) ;; guessed by decompiler ) :method-count-assert 14 @@ -4259,8 +4261,9 @@ ) (deftype dma-gif (structure) + "Believed unused GIF header type." ((gif uint64 2 :offset-assert 0) ;; guessed by decompiler - (quad uint128 :offset 0) + (quad uint128 :offset-assert 0 :overlay-at gif) ) :method-count-assert 9 :size-assert #x10 @@ -4268,9 +4271,10 @@ ) (deftype dma-gif-packet (structure) + "The header for a DMA transfer that goes directly to GIF, containing DMA, VIF, GIF tags." ((dma-vif dma-packet :inline :offset-assert 0) (gif uint64 2 :offset-assert 16) ;; guessed by decompiler - (quad uint128 2 :offset 0) ;; guessed by decompiler + (quad uint128 2 :offset-assert 0 :overlay-at dma-vif) ;; guessed by decompiler ) :method-count-assert 9 :size-assert #x20 @@ -4278,12 +4282,16 @@ ) (deftype dma-buffer (basic) + "A buffer for DMA data." ((allocated-length int32 :offset-assert 4) (base pointer :offset-assert 8) ;; guessed by decompiler (end pointer :offset-assert 12) ;; guessed by decompiler (real-buffer-end int32 :offset-assert 16) (data uint64 1 :offset 32) ;; guessed by decompiler ) + (:methods + (new "Allocate a DMA buffer to hold the given size" (symbol type int) _type_) ;; 0 + ) :method-count-assert 9 :size-assert #x28 :flag-assert #x900000028 @@ -4292,20 +4300,33 @@ ) ) -;; (define-extern dma-buffer-inplace-new function) ;; (function dma-buffer int dma-buffer) -;; (define-extern dma-buffer-length function) ;; (function dma-buffer int) -;; (define-extern dma-buffer-free function) ;; (function dma-buffer int) -;; (define-extern dma-buffer-add-vu-function function) ;; (function dma-buffer vu-function int symbol) -;; (define-extern dma-buffer-send function) ;; (function dma-bank dma-buffer none) -;; (define-extern dma-buffer-send-chain function) ;; (function dma-bank-source dma-buffer none) +(define-extern dma-buffer-inplace-new + "Create a dma-buffer in-place. Does not set the type of the dma-buffer object." + (function dma-buffer int dma-buffer)) +(define-extern dma-buffer-length + "Get length used in quadwords, rounded up." + (function dma-buffer int)) +(define-extern dma-buffer-free + "Get the number of free quadwords between base and end pointers." + (function dma-buffer int)) +(define-extern dma-buffer-add-vu-function + "Add DMA tags to load the given VU function. The destination in vu instruction memory + is specific inside the vu-function. This does NOT copy the vu-function into the buffer, + but creates a reference to the existing VU function." (function dma-buffer vu-function int symbol)) +(define-extern dma-buffer-send + "Send the DMA buffer! DOES NOT TRANSFER TAG, you probably want dma-buffer-send-chain instead." + (function dma-bank dma-buffer none)) +(define-extern dma-buffer-send-chain + "Send the DMA buffer! Sends the tags, so this is suitable for the main graphics chain." + (function dma-bank-source dma-buffer none)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; dma-bucket ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; (define-extern dma-buffer-add-buckets function) ;; (function dma-buffer int (inline-array dma-bucket)) -;; (define-extern dma-buffer-patch-buckets function) ;; (function (inline-array dma-bucket) int (inline-array dma-bucket)) -;; (define-extern dma-bucket-insert-tag function) ;; (function (inline-array dma-bucket) bucket-id pointer (pointer dma-tag) pointer) +(define-extern dma-buffer-add-buckets "Initialize an array of dma-buckets in a DMA buffer." (function dma-buffer int (inline-array dma-bucket))) +(define-extern dma-buffer-patch-buckets "Patch together DMA buckets after they have been filled." (function dma-bucket int dma-bucket)) +(define-extern dma-bucket-insert-tag "Add a dma chain to the bucket." (function (inline-array dma-bucket) bucket-id pointer (pointer dma-tag) pointer)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; dma-disasm ;; @@ -4464,7 +4485,7 @@ :size-assert #x10 :flag-assert #x900000010 (:methods - (new + (new "Create a cpad-list for 2 controllers. It's fine to do this even if one or both controllers aren't connected yet." (symbol type) _type_) ;; 0 @@ -5519,7 +5540,7 @@ and arg2 is down (-y). Will have the pitch of forward." (function matrix vector vector matrix)) (define-extern forward-down-nopitch->inv-matrix - "Create a matrix representing an inverse transform where arg1 is forward (+z) + "Create a matrix representing an inverse transform where arg1 is forward (+z) and arg2 is down (-y). Will not use the pitch of forward." (function matrix vector vector matrix)) (define-extern forward-up->inv-matrix @@ -7712,7 +7733,7 @@ "The math-camera matrices are used to compute fogging values, which are a per-vertex uint8 that tells the GS how 'foggy' the color should be. This should be proportional to how far away the vertex is. There is a scaling factor applied so the fog intensity isn't affected by the field of view angle. - + The fog-corrector stores a fog-end fog-start value that is corrected for the field of view. The actual correction factor is computed in cam-update.gc. Without this corrector, the fogginess of the world would change as the FOV changes @@ -8151,7 +8172,7 @@ (deftype connectable (structure) "A connectable is the linked-list node part of a connection. The connections themselves are owned by the engine. - + The `next0`/`prev0` references are used for how this belongs in the connectable list belonging to the [[engine]]. These terminate on special nodes stored in the engine: `alive-list`/`alive-list-end` for the active connections, and `dead-list`/`dead-list-end` @@ -8244,7 +8265,7 @@ "Add a connection between this engine and a given process." (engine process object object object object) connection) ;; 15 (remove-from-process "Remove all connections from process for this engine." (engine process) int) ;; 16 - (remove-matching + (remove-matching "Call the given function on each connection and the engine. If it returns truthy, `move-to-dead` that connection." (engine (function connection engine symbol)) int) ;; 17 @@ -11167,7 +11188,7 @@ ;; (define-extern *stats-bsp* object) ;; symbol ;; (define-extern *stats-buffer* object) ;; symbol ;; (define-extern *stats-target* object) ;; symbol -;; (define-extern *stats-profile-bars* object) ;; symbol +(define-extern *stats-profile-bars* symbol) ;; (define-extern *stats-perf* object) ;; symbol ;; (define-extern *artist-all-visible* object) ;; symbol ;; (define-extern *artist-flip-visible* object) ;; symbol @@ -11175,7 +11196,7 @@ ;; (define-extern *artist-fix-frustum* object) ;; symbol ;; (define-extern *artist-error-spheres* object) ;; symbol ;; (define-extern *artist-use-menu-subdiv* object) ;; symbol -;; (define-extern *display-profile* object) ;; symbol +(define-extern *display-profile* symbol) ;; (define-extern *display-sidekick-stats* object) ;; symbol ;; (define-extern *display-quad-stats* object) ;; symbol ;; (define-extern *display-tri-stats* object) ;; symbol @@ -11211,7 +11232,7 @@ ;; (define-extern *display-sprite-marks* object) ;; symbol ;; (define-extern *display-sprite-spheres* object) ;; symbol ;; (define-extern *display-entity-errors* object) ;; symbol -;; (define-extern *display-capture-mode* object) +(define-extern *display-capture-mode* symbol) ;; (define-extern *display-instance-info* object) ;; symbol ;; (define-extern *display-deci-count* object) ;; symbol ;; (define-extern *sync-dma* object) ;; symbol diff --git a/decompiler/config/jak3/ntsc_v1/type_casts.jsonc b/decompiler/config/jak3/ntsc_v1/type_casts.jsonc index 592931fdc1d..af3babe627b 100644 --- a/decompiler/config/jak3/ntsc_v1/type_casts.jsonc +++ b/decompiler/config/jak3/ntsc_v1/type_casts.jsonc @@ -197,5 +197,20 @@ [96, "t2", "(pointer gs-xyzf)"], [97, "t2", "(pointer uint64)"], [[110, 117], "v1", "(pointer uint64)"] + ], + "dma-bucket-insert-tag": [ + [[2, 6], "v1", "dma-bucket"], + [3, "a0", "dma-bucket"] + ], + "dma-buffer-add-buckets": [ + [[1, 4], "v1", "dma-bucket"], + [5, "v1", "pointer"], + [[9, 11], "v1", "dma-bucket"], + [11, "v1", "pointer"] + ], + "dma-buffer-patch-buckets": [ + [[3, 34], "a0", "dma-bucket"], + [[34, 38], "a0", "dma-packet"] + // [34, "a0", "(inline-array dma-bucket)"] ] } diff --git a/decompiler/config/jak3/ntsc_v1/var_names.jsonc b/decompiler/config/jak3/ntsc_v1/var_names.jsonc index 73470414e5d..d18d61afb82 100644 --- a/decompiler/config/jak3/ntsc_v1/var_names.jsonc +++ b/decompiler/config/jak3/ntsc_v1/var_names.jsonc @@ -458,5 +458,35 @@ "vars": { "gp-0": "mouse" } + }, + "(method 0 dma-buffer)": { + "args": ["allocation", "type-to-make", "size-bytes"] + }, + "dma-buffer-inplace-new": { + "args": ["dma-buff", "size-bytes"] + }, + "dma-buffer-length": { + "args": ["dma-buf"] + }, + "dma-buffer-free": { + "args": ["dma-buf"] + }, + "dma-buffer-add-vu-function": { + "args": ["dma-buf", "vu-func", "flush-path-3"] + }, + "dma-buffer-send": { + "args": ["chan", "buf"] + }, + "dma-buffer-send-chain": { + "args": ["chan", "buf"] + }, + "dma-buffer-patch-buckets": { + "args": ["base", "count"] + }, + "dma-buffer-add-buckets": { + "args": ["dma-buf", "bucket-count"] + }, + "dma-bucket-insert-tag": { + "args": ["buckets", "bucket", "start-tag", "end-tag-to-patch"] } } diff --git a/goal_src/jak3/engine/dma/dma-bucket.gc b/goal_src/jak3/engine/dma/dma-bucket.gc index 70a9352b7b6..f9c4026c14d 100644 --- a/goal_src/jak3/engine/dma/dma-bucket.gc +++ b/goal_src/jak3/engine/dma/dma-bucket.gc @@ -7,3 +7,63 @@ ;; DECOMP BEGINS +;; WARN: Return type mismatch pointer vs (inline-array dma-bucket). +(defun dma-buffer-add-buckets ((dma-buf dma-buffer) (bucket-count int)) + "Initialize an array of dma-buckets in a DMA buffer." + (let ((v0-0 (-> dma-buf base))) + (let ((v1-0 (the-as object v0-0))) + (dotimes (a2-0 bucket-count) + (set! (-> (the-as dma-bucket v1-0) tag) + (new 'static 'dma-tag :id (dma-tag-id next) :addr (the-as int (&+ (the-as pointer v1-0) 16))) + ) + (set! (-> (the-as dma-bucket v1-0) last) (the-as (pointer dma-tag) v1-0)) + (set! v1-0 (&+ (the-as pointer v1-0) 16)) + ) + (set! (-> dma-buf base) (the-as pointer v1-0)) + ) + (the-as (inline-array dma-bucket) v0-0) + ) + ) + +(defun dma-buffer-patch-buckets ((base dma-bucket) (count int)) + "Patch together DMA buckets after they have been filled." + (when (nonzero? base) + (dotimes (v1-1 count) + (cond + ((= base (-> base last)) + (set! (-> base tag) (new 'static 'dma-tag :id (dma-tag-id cnt))) + (set! (-> base clear) (the-as uint 0)) + 0 + ) + (else + (set! (-> base last 0 addr) (the-as int (&+ base 16))) + (cond + ((and (or *display-profile* *stats-profile-bars*) (not *display-capture-mode*)) + (set! (-> (the-as dma-packet base) vif0) (new 'static 'vif-tag :cmd (vif-cmd mark) :imm v1-1)) + (set! (-> (the-as dma-packet base) vif1) (new 'static 'vif-tag :irq #x1)) + ) + (else + (set! (-> base clear) (the-as uint 0)) + 0 + ) + ) + ) + ) + (&+! base 16) + ) + ) + base + ) + +(defun dma-bucket-insert-tag ((buckets (inline-array dma-bucket)) + (bucket bucket-id) + (start-tag pointer) + (end-tag-to-patch (pointer dma-tag)) + ) + "Add a dma chain to the bucket." + (let ((v1-1 (-> buckets bucket))) + (set! (-> (the-as dma-bucket (-> v1-1 last)) next) (the-as uint start-tag)) + (set! (-> v1-1 last) end-tag-to-patch) + ) + start-tag + ) diff --git a/goal_src/jak3/engine/dma/dma-buffer.gc b/goal_src/jak3/engine/dma/dma-buffer.gc index 95e14598ec6..c337ee3560e 100644 --- a/goal_src/jak3/engine/dma/dma-buffer.gc +++ b/goal_src/jak3/engine/dma/dma-buffer.gc @@ -205,6 +205,79 @@ ) ) +(defmacro with-cnt-vif-block (bindings &rest body) + "Start a cnt w/ vif direct to gif dma packet setup for the dma-buffer in bindings. + With this, you can transfer data through PATH2 without having to setup the tag yourself. + The qwc of the transfer is determined at runtime at the end of this block." + + (let ((buf (first bindings))) + + (with-gensyms (buf-start buf-qwc) + `(let ((,buf-start (-> ,buf base))) + + ;; setup the dmatag for PATH2 transfer, qwc is 0 (patched later) + (dma-buffer-add-cnt-vif2 ,buf 0 + (new 'static 'vif-tag :cmd (vif-cmd nop)) + (new 'static 'vif-tag :cmd (vif-cmd direct)) + ) + + ;; things with this buffer! + ,@body + + ;; patch qwc! just do the difference between the current ptr and the old one and turn it into qwords. + ;; we take one qword out because it's the initial dmatag which isnt part of the count. + ;; this rounds *down*, so make sure to fill the buffer in 128-bit boundaries. + (let ((,buf-qwc (/ (+ (&- -16 ,buf-start) (the int (-> ,buf base))) 16))) + (cond + ((nonzero? ,buf-qwc) ;; stuff was added to the buffer + ;; patch the DMA tag + (logior! (-> (the-as (pointer dma-tag) ,buf-start) 0) (the-as uint (new 'static 'dma-tag :qwc ,buf-qwc))) + ;; patch the 2nd vifcode's imm field (qwc) + (logior! (-> (the-as (pointer dma-tag) ,buf-start) 1) (the-as uint (shl (shr (shl ,buf-qwc 48) 48) 32))) + ) + (else ;; nothing was added to the buffer. delete the dmatag, you cannot transfer 0 qwords. + (set! (-> ,buf base) ,buf-start) + ) + ) + ) + ) + + )) + ) + +(defmacro with-cnt-vif-block-qwc (bindings &rest body) + "Start a cnt w/ vif direct to gif dma packet setup for the dma-buffer in bindings. + With this, you can transfer data through PATH2 without having to setup the tag yourself. + The qwc of the transfer is determined at runtime at the end of this block. + WARNING: You MUST guarantee that the resulting qwc is NOT zero!" + + (let ((buf (first bindings))) + + (with-gensyms (buf-start buf-qwc) + `(let ((,buf-start (the-as dma-packet (-> ,buf base)))) + ;; dmatag will be added at the end so we reserve + (&+! (-> ,buf base) 16) + + ;; setup the dmatag for PATH2 transfer, qwc is 0 (patched later) + (dma-buffer-add-cnt-vif2 ,buf 0 + (new 'static 'vif-tag :cmd (vif-cmd nop)) + (new 'static 'vif-tag :cmd (vif-cmd direct)) + ) + + ;; things with this buffer! + ,@body + + ;; we make the dmatag now! its at the start. + (let ((,buf-qwc (/ (+ (- -16 (the-as int ,buf-start)) (the-as int (-> ,buf base))) 16))) + (set! (-> ,buf-start dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc ,buf-qwc)) + (set! (-> ,buf-start vif0) (new 'static 'vif-tag)) + (set! (-> ,buf-start vif1) (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1 :imm ,buf-qwc)) + ) + ) + + )) + ) + (defmacro with-dma-bucket (bindings &rest body) "Start a new dma-bucket in body that will be finished at the end. The bindings are the dma-buffer, dma-bucket and bucket-id respectively." @@ -257,6 +330,7 @@ ;; DECOMP BEGINS (deftype dma-packet (structure) + "The header for a DMA transfer, containing an DMA tag, and VIF tags." ((dma dma-tag) (vif0 vif-tag) (vif1 vif-tag) @@ -266,6 +340,7 @@ (deftype dma-packet-array (inline-array-class) + "Unused dma array. Unclear how it should be used." ((data dma-packet :dynamic) ) ) @@ -274,6 +349,7 @@ (set! (-> dma-packet-array heap-base) (the-as uint 16)) (deftype dma-gif (structure) + "Believed unused GIF header type." ((gif uint64 2) (quad uint128 :overlay-at (-> gif 0)) ) @@ -281,6 +357,7 @@ (deftype dma-gif-packet (structure) + "The header for a DMA transfer that goes directly to GIF, containing DMA, VIF, GIF tags." ((dma-vif dma-packet :inline) (gif uint64 2) (quad uint128 2 :overlay-at (-> dma-vif dma)) @@ -289,6 +366,7 @@ (deftype dma-buffer (basic) + "A buffer for DMA data." ((allocated-length int32) (base pointer) (end pointer) @@ -300,3 +378,92 @@ ) ) + +(defmethod new dma-buffer ((allocation symbol) (type-to-make type) (size-bytes int)) + "Allocate a DMA buffer to hold the given size" + (let ((v0-0 (object-new allocation type-to-make (+ size-bytes -4 (-> type-to-make size))))) + (set! (-> v0-0 base) (-> v0-0 data)) + (set! (-> v0-0 allocated-length) size-bytes) + (set! (-> v0-0 real-buffer-end) (the-as int (&+ (-> v0-0 data) size-bytes))) + v0-0 + ) + ) + +(defun dma-buffer-inplace-new ((dma-buff dma-buffer) (size-bytes int)) + "Create a dma-buffer in-place. Does not set the type of the dma-buffer object." + (set! (-> dma-buff base) (-> dma-buff data)) + (set! (-> dma-buff allocated-length) size-bytes) + dma-buff + ) + +(defmethod length ((this dma-buffer)) + (-> this allocated-length) + ) + +(defmethod asize-of ((this dma-buffer)) + (+ (-> this allocated-length) -4 (-> dma-buffer size)) + ) + +(defun dma-buffer-length ((dma-buf dma-buffer)) + "Get length used in quadwords, rounded up." + (shr (+ (&- (-> dma-buf base) (the-as uint (-> dma-buf data))) 15) 4) + ) + +(defun dma-buffer-free ((dma-buf dma-buffer)) + "Get the number of free quadwords between base and end pointers." + (shr (+ (&- (-> dma-buf end) (the-as uint (-> dma-buf base))) 15) 4) + ) + +;; ERROR: Failed store: (s.w! (+ t2-0 8) t3-5) at op 23 +;; ERROR: Failed store: (s.w! (+ t2-0 12) t3-8) at op 32 +(defun dma-buffer-add-vu-function ((dma-buf dma-buffer) (vu-func vu-function) (flush-path-3 int)) + "Add DMA tags to load the given VU function. The destination in vu instruction memory + is specific inside the vu-function. This does NOT copy the vu-function into the buffer, + but creates a reference to the existing VU function." + + ;; The first 4 bytes of a vu-function object's data are discarded because they aren't aligned. + (let ((func-ptr (the-as pointer (&-> vu-func data 4))) + (qlen (-> vu-func qlength)) ;; number of quadwords + (origin (-> vu-func origin)) ;; destination address in VU instruction memory. + ) + ;; loop until whole program is transferred. + (while (> qlen 0) + ;; transfer up to 127 quadwords at a single time. + (let ((qwc-now (min 127 qlen))) + ;; Set up DMA to transfer the data from the vu-function + ;; ref id = reference to data outside of the buffer. + (dma-buffer-add-ref-vif2 dma-buf qwc-now func-ptr + ;; Set up first vifcode as a flush. + (new 'static 'vif-tag :cmd (if (zero? flush-path-3) (vif-cmd flushe) (vif-cmd flusha))) + ;; next vifcode, transfer microprogram. This is in 64-bit units (VU instructions) + (new 'static 'vif-tag :cmd (vif-cmd mpg) :num (shl qwc-now 1) :imm origin) + ) + ;; increment by qwc-now quadwords. + (&+! func-ptr (shl qwc-now 4)) + (set! qlen (- qlen qwc-now)) + (+! origin (shl qwc-now 1)) + ) + ) + ) + #f + ) + +(defun dma-buffer-send ((chan dma-bank) (buf dma-buffer)) + "Send the DMA buffer! DOES NOT TRANSFER TAG, you probably want dma-buffer-send-chain instead." + (when (< (-> buf allocated-length) (&- (-> buf base) (the-as uint (-> buf data)))) + (crash!) + 0 + ) + (dma-send chan (the-as uint (-> buf data)) (the-as uint (dma-buffer-length buf))) + (none) + ) + +(defun dma-buffer-send-chain ((chan dma-bank-source) (buf dma-buffer)) + "Send the DMA buffer! Sends the tags, so this is suitable for the main graphics chain." + (when (< (-> buf allocated-length) (&- (-> buf base) (the-as uint (-> buf data)))) + (crash!) + 0 + ) + (dma-send-chain chan (the-as uint (-> buf data))) + (none) + ) diff --git a/goal_src/jak3/engine/dma/dma.gc b/goal_src/jak3/engine/dma/dma.gc index c8c7ce27b4b..661801eb787 100644 --- a/goal_src/jak3/engine/dma/dma.gc +++ b/goal_src/jak3/engine/dma/dma.gc @@ -7,3 +7,157 @@ ;; DECOMP BEGINS + +(defun dma-sync-hang ((bank dma-bank)) + "Hang here until the dma transfer is completed. + This is worse than the dma-sync-fast because it ends + up spamming the DMA bank register more often, and reduces + the speed of the DMA transfer. + This function is unused." + (crash!) + (none) + ) + +(defun dma-sync-crash ((arg0 dma-bank)) + "Wait for DMA to finish for a while, then crash if we can't. + This function is unused." + (crash!) + (none) + ) + +(defun dma-send ((arg0 dma-bank) (madr uint) (qwc uint)) + "Send DMA given an address and a quadword count. + The madr can be in main memory or scratchpad. + This is appropriate for VIF0/GIF transfers. + It can be used for VIF1, but will do VIF -> madr, which is probably + not what you want." + (crash!) + (none) + ) + +(defun dma-send-chain ((arg0 dma-bank-source) (tadr uint)) + "Send DMA! tadr should be a tag address, possibly in spad ram. + This is useful for sending to VIF. + Tag transfer is enabled, and DIR is set so a VIF1 transfer + goes from tadr -> VIF." + (crash!) + (none) + ) + +(defun dma-send-chain-no-tte ((arg0 dma-bank-source) (arg1 uint)) + "Send DMA chain! TTE bit is not set, don't transfer tags. + This is never used." + (crash!) + (none) + ) + +(defun dma-send-chain-no-flush ((arg0 dma-bank-source) (arg1 uint)) + "Send DMA chain! But don't flush the cache, so be careful here. TTE enable." + (crash!) + (none) + ) + +(defun dma-send-to-spr ((sadr uint) (madr uint) (qwc uint) (sync symbol)) + "Transfer data to spr" + (crash!) + (none) + ) + +(defun dma-send-to-spr-no-flush ((sadr uint) (madr uint) (qwc uint) (sync symbol)) + "Transfer to spr. Doesn't flush the cache first, so be careful." + (crash!) + (none) + ) + +(defun dma-send-from-spr ((madr uint) (sadr uint) (qwc uint) (sync symbol)) + "Transfer from spr." + (crash!) + (none) + ) + +(defun dma-send-from-spr-no-flush ((madr uint) (sadr uint) (qwc uint) (sync symbol)) + "Transfer from spr, don't flush the cache." + (crash!) + (none) + ) + +(defun dma-initialize () + "Due to a bug in the PS2 hardware, you must always disable the DMAtag mismatch + error. This is done here." + + (#when PC_PORT + (return 0) + ) + + (set! (-> (the-as vif-bank #x10003800) err me0) 1) + (set! (-> (the-as vif-bank #x10003c00) err me0) 1) + (none) + ) + +(defun clear-vu0-mem () + "Set the vu0 data memory to 0xabadbeef. This uses the slow EE mapping of VU memory. + Will crash on PC Port." + (crash!) + (none) + ) + +(defun clear-vu1-mem () + "Set the vu1 data memory to 0xabadbeef. This uses the slow EE mapping of VU memory. + Will crash on PC Port." + (crash!) + (none) + ) + +(defun dump-vu1-mem () + "Print VU1 memory to runtime stdout. + Will crash on PC Port." + (crash!) + (none) + ) + +(defun dump-vu1-range ((start uint) (total-count uint)) + "Print part of VU1 memory to runtime stdout. + Will crash on PC Port." + (crash!) + #f + ) + +(defun reset-vif1-path () + "When things go wrong, totally reset vif1." + (#unless PC_PORT + ;; changed for jak 3! now prints to 0. + (format 0 "~`dma-bank-vif`I~`vif-bank`I" #x10009000 #x10003c00) + ) + (reset-path) + (set-graphics-mode) + (format 0 "gkernel: vif1 path reset!~%") + (none) + ) + +(defun ultimate-memcpy ((dst pointer) (src pointer) (size-bytes uint)) + "The Fastest Memory Copy, for larger transfers. + Memory is copied in ascending order, in 4 kB blocks. + The size should be a multiple of 16 bytes." + ;; on PC Port, just call C mem-move, it's the fastest. + (__mem-move dst src size-bytes) + (none) + ) + +(defun symlink2 () + "symlink2 is a handwritten assembly version of the v2 linking routine. + it is not ported because the OpenGOAL linker has its own implementation already." + (crash!) + (none) + ) + +(defun symlink3 () + "symlink3 is a handwritten assembly version of the v3 linking routine. + OpenGOAL uses a different format for v3, customized for x86-64, so this is not + needed. The C++ implementation is plenty fast enough" + (crash!) + (none) + ) + +;; configuration required to work around hardware bug on the PS2. +;; doesn't do anything important +(dma-initialize) \ No newline at end of file diff --git a/goal_src/jak3/engine/gfx/hw/video-h.gc b/goal_src/jak3/engine/gfx/hw/video-h.gc index 4f17968a6a2..0669f032e03 100644 --- a/goal_src/jak3/engine/gfx/hw/video-h.gc +++ b/goal_src/jak3/engine/gfx/hw/video-h.gc @@ -5,6 +5,7 @@ ;; name in dgo: video-h ;; dgos: GAME +(define-extern set-graphics-mode (function none)) (define-extern get-video-mode (function symbol)) ;; DECOMP BEGINS diff --git a/goal_src/jak3/engine/util/profile-h.gc b/goal_src/jak3/engine/util/profile-h.gc index 6df52a4cf30..60368f05b7d 100644 --- a/goal_src/jak3/engine/util/profile-h.gc +++ b/goal_src/jak3/engine/util/profile-h.gc @@ -6,6 +6,9 @@ ;; dgos: GAME (declare-type dma-buffer structure) +(define-extern *display-profile* symbol) +(define-extern *stats-profile-bars* symbol) +(define-extern *display-capture-mode* symbol) ;; DECOMP BEGINS diff --git a/test/decompiler/reference/jak3/engine/dma/dma-bucket_REF.gc b/test/decompiler/reference/jak3/engine/dma/dma-bucket_REF.gc new file mode 100644 index 00000000000..93131d7ca0d --- /dev/null +++ b/test/decompiler/reference/jak3/engine/dma/dma-bucket_REF.gc @@ -0,0 +1,73 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for function dma-buffer-add-buckets +;; WARN: Return type mismatch pointer vs (inline-array dma-bucket). +(defun dma-buffer-add-buckets ((dma-buf dma-buffer) (bucket-count int)) + "Initialize an array of dma-buckets in a DMA buffer." + (let ((v0-0 (-> dma-buf base))) + (let ((v1-0 (the-as object v0-0))) + (dotimes (a2-0 bucket-count) + (set! (-> (the-as dma-bucket v1-0) tag) + (new 'static 'dma-tag :id (dma-tag-id next) :addr (the-as int (&+ (the-as pointer v1-0) 16))) + ) + (set! (-> (the-as dma-bucket v1-0) last) (the-as (pointer dma-tag) v1-0)) + (set! v1-0 (&+ (the-as pointer v1-0) 16)) + ) + (set! (-> dma-buf base) (the-as pointer v1-0)) + ) + (the-as (inline-array dma-bucket) v0-0) + ) + ) + +;; definition for function dma-buffer-patch-buckets +(defun dma-buffer-patch-buckets ((base dma-bucket) (count int)) + "Patch together DMA buckets after they have been filled." + (when (nonzero? base) + (dotimes (v1-1 count) + (cond + ((= base (-> base last)) + (set! (-> base tag) (new 'static 'dma-tag :id (dma-tag-id cnt))) + (set! (-> base clear) (the-as uint 0)) + 0 + ) + (else + (set! (-> base last 0 addr) (the-as int (&+ base 16))) + (cond + ((and (or *display-profile* *stats-profile-bars*) (not *display-capture-mode*)) + (set! (-> (the-as dma-packet base) vif0) (new 'static 'vif-tag :cmd (vif-cmd mark) :imm v1-1)) + (set! (-> (the-as dma-packet base) vif1) (new 'static 'vif-tag :irq #x1)) + ) + (else + (set! (-> base clear) (the-as uint 0)) + 0 + ) + ) + ) + ) + (&+! base 16) + ) + ) + base + ) + +;; definition for function dma-bucket-insert-tag +(defun dma-bucket-insert-tag ((buckets (inline-array dma-bucket)) + (bucket bucket-id) + (start-tag pointer) + (end-tag-to-patch (pointer dma-tag)) + ) + "Add a dma chain to the bucket." + (let ((v1-1 (-> buckets bucket))) + (set! (-> (the-as dma-bucket (-> v1-1 last)) next) (the-as uint start-tag)) + (set! (-> v1-1 last) end-tag-to-patch) + ) + start-tag + ) + +;; failed to figure out what this is: +0 + + + + diff --git a/test/decompiler/reference/jak3/engine/dma/dma-buffer_REF.gc b/test/decompiler/reference/jak3/engine/dma/dma-buffer_REF.gc new file mode 100644 index 00000000000..452b8e45a52 --- /dev/null +++ b/test/decompiler/reference/jak3/engine/dma/dma-buffer_REF.gc @@ -0,0 +1,241 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition of type dma-packet +(deftype dma-packet (structure) + "The header for a DMA transfer, containing an DMA tag, and VIF tags." + ((dma dma-tag) + (vif0 vif-tag) + (vif1 vif-tag) + (quad uint128 :overlay-at dma) + ) + ) + +;; definition for method 3 of type dma-packet +;; INFO: Used lq/sq +(defmethod inspect ((this dma-packet)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this 'dma-packet) + (format #t "~1Tdma: #x~X~%" (-> this dma)) + (format #t "~1Tvif0: #x~X~%" (-> this vif0)) + (format #t "~1Tvif1: #x~X~%" (-> this vif1)) + (format #t "~1Tquad: ~D~%" (-> this quad)) + (label cfg-4) + this + ) + +;; definition of type dma-packet-array +(deftype dma-packet-array (inline-array-class) + "Unused dma array. Unclear how it should be used." + ((data dma-packet :dynamic) + ) + ) + +;; definition for method 3 of type dma-packet-array +(defmethod inspect ((this dma-packet-array)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this (-> this type)) + (format #t "~1Tlength: ~D~%" (-> this length)) + (format #t "~1Tallocated-length: ~D~%" (-> this allocated-length)) + (format #t "~1Tdata[0] @ #x~X~%" (-> this data)) + (label cfg-4) + this + ) + +;; failed to figure out what this is: +(set! (-> dma-packet-array heap-base) (the-as uint 16)) + +;; definition of type dma-gif +(deftype dma-gif (structure) + "Believed unused GIF header type." + ((gif uint64 2) + (quad uint128 :overlay-at (-> gif 0)) + ) + ) + +;; definition for method 3 of type dma-gif +;; INFO: Used lq/sq +(defmethod inspect ((this dma-gif)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this 'dma-gif) + (format #t "~1Tgif[2] @ #x~X~%" (-> this gif)) + (format #t "~1Tquad: ~D~%" (-> this quad)) + (label cfg-4) + this + ) + +;; definition of type dma-gif-packet +(deftype dma-gif-packet (structure) + "The header for a DMA transfer that goes directly to GIF, containing DMA, VIF, GIF tags." + ((dma-vif dma-packet :inline) + (gif uint64 2) + (quad uint128 2 :overlay-at (-> dma-vif dma)) + ) + ) + +;; definition for method 3 of type dma-gif-packet +(defmethod inspect ((this dma-gif-packet)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this 'dma-gif-packet) + (format #t "~1Tdma-vif: #~%" (-> this dma-vif)) + (format #t "~1Tgif[2] @ #x~X~%" (-> this gif)) + (format #t "~1Tquad[2] @ #x~X~%" (-> this dma-vif)) + (label cfg-4) + this + ) + +;; definition of type dma-buffer +(deftype dma-buffer (basic) + "A buffer for DMA data." + ((allocated-length int32) + (base pointer) + (end pointer) + (real-buffer-end int32) + (data uint64 1 :offset 32) + ) + (:methods + (new (symbol type int) _type_) + ) + ) + +;; definition for method 3 of type dma-buffer +(defmethod inspect ((this dma-buffer)) + (when (not this) + (set! this this) + (goto cfg-4) + ) + (format #t "[~8x] ~A~%" this (-> this type)) + (format #t "~1Tallocated-length: ~D~%" (-> this allocated-length)) + (format #t "~1Tbase: #x~X~%" (-> this base)) + (format #t "~1Tend: #x~X~%" (-> this end)) + (format #t "~1Treal-buffer-end: ~D~%" (-> this real-buffer-end)) + (format #t "~1Tdata[1] @ #x~X~%" (-> this data)) + (label cfg-4) + this + ) + +;; definition for method 0 of type dma-buffer +(defmethod new dma-buffer ((allocation symbol) (type-to-make type) (size-bytes int)) + "Allocate a DMA buffer to hold the given size" + (let ((v0-0 (object-new allocation type-to-make (+ size-bytes -4 (-> type-to-make size))))) + (set! (-> v0-0 base) (-> v0-0 data)) + (set! (-> v0-0 allocated-length) size-bytes) + (set! (-> v0-0 real-buffer-end) (the-as int (&+ (-> v0-0 data) size-bytes))) + v0-0 + ) + ) + +;; definition for function dma-buffer-inplace-new +(defun dma-buffer-inplace-new ((dma-buff dma-buffer) (size-bytes int)) + "Create a dma-buffer in-place. Does not set the type of the dma-buffer object." + (set! (-> dma-buff base) (-> dma-buff data)) + (set! (-> dma-buff allocated-length) size-bytes) + dma-buff + ) + +;; definition for method 4 of type dma-buffer +(defmethod length ((this dma-buffer)) + (-> this allocated-length) + ) + +;; definition for method 5 of type dma-buffer +(defmethod asize-of ((this dma-buffer)) + (+ (-> this allocated-length) -4 (-> dma-buffer size)) + ) + +;; definition for function dma-buffer-length +(defun dma-buffer-length ((dma-buf dma-buffer)) + "Get length used in quadwords, rounded up." + (shr (+ (&- (-> dma-buf base) (the-as uint (-> dma-buf data))) 15) 4) + ) + +;; definition for function dma-buffer-free +(defun dma-buffer-free ((dma-buf dma-buffer)) + "Get the number of free quadwords between base and end pointers." + (shr (+ (&- (-> dma-buf end) (the-as uint (-> dma-buf base))) 15) 4) + ) + +;; definition for function dma-buffer-add-vu-function +;; ERROR: Failed store: (s.w! (+ t2-0 8) t3-5) at op 23 +;; ERROR: Failed store: (s.w! (+ t2-0 12) t3-8) at op 32 +(defun dma-buffer-add-vu-function ((dma-buf dma-buffer) (vu-func vu-function) (flush-path-3 int)) + "Add DMA tags to load the given VU function. The destination in vu instruction memory + is specific inside the vu-function. This does NOT copy the vu-function into the buffer, + but creates a reference to the existing VU function." + (let ((v1-0 (the-as object (+ (the-as uint vu-func) 16))) + (a3-0 (-> vu-func qlength)) + (a1-1 (-> vu-func origin)) + ) + (while (> a3-0 0) + (let ((t0-1 (min 127 a3-0))) + (let* ((t1-1 dma-buf) + (t2-0 (-> t1-1 base)) + ) + (set! (-> (the-as (pointer int64) t2-0)) + (logior (logior #x30000000 (shr (shl t0-1 48) 48)) (shr (shl (the-as int v1-0) 33) 1)) + ) + (let ((t3-5 (shr + (shl + (if (zero? flush-path-3) + 16 + 19 + ) + 57 + ) + 33 + ) + ) + ) + (s.w! (+ t2-0 8) t3-5) + ) + (let ((t3-8 (logior (logior #x4a000000 (shr (shl a1-1 48) 48)) (shr (shl (* t0-1 2) 56) 40)))) + (s.w! (+ t2-0 12) t3-8) + ) + (set! (-> t1-1 base) (&+ t2-0 16)) + ) + (set! v1-0 (+ (the-as uint v1-0) (* t0-1 16))) + (set! a3-0 (- a3-0 t0-1)) + (+! a1-1 (* t0-1 2)) + ) + ) + ) + #f + ) + +;; definition for function dma-buffer-send +(defun dma-buffer-send ((chan dma-bank) (buf dma-buffer)) + "Send the DMA buffer! DOES NOT TRANSFER TAG, you probably want dma-buffer-send-chain instead." + (when (< (-> buf allocated-length) (&- (-> buf base) (the-as uint (-> buf data)))) + (crash!) + 0 + ) + (dma-send chan (the-as uint (-> buf data)) (the-as uint (dma-buffer-length buf))) + (none) + ) + +;; definition for function dma-buffer-send-chain +(defun dma-buffer-send-chain ((chan dma-bank-source) (buf dma-buffer)) + "Send the DMA buffer! Sends the tags, so this is suitable for the main graphics chain." + (when (< (-> buf allocated-length) (&- (-> buf base) (the-as uint (-> buf data)))) + (crash!) + 0 + ) + (dma-send-chain chan (the-as uint (-> buf data))) + (none) + ) + + + + diff --git a/test/decompiler/reference/jak3/engine/geometry/geometry_REF.gc b/test/decompiler/reference/jak3/engine/geometry/geometry_REF.gc index 039451974a2..c3cf13c0db4 100644 --- a/test/decompiler/reference/jak3/engine/geometry/geometry_REF.gc +++ b/test/decompiler/reference/jak3/engine/geometry/geometry_REF.gc @@ -428,7 +428,7 @@ ;; definition for function forward-down-nopitch->inv-matrix ;; INFO: Used lq/sq (defun forward-down-nopitch->inv-matrix ((arg0 matrix) (arg1 vector) (arg2 vector)) - "Create a matrix representing an inverse transform where arg1 is forward (+z) + "Create a matrix representing an inverse transform where arg1 is forward (+z) and arg2 is down (-y). Will not use the pitch of forward." (vector-normalize-copy! (-> arg0 uvec) arg2 1.0) (vector-negate! (-> arg0 uvec) (-> arg0 uvec)) @@ -2048,7 +2048,3 @@ ) arg0 ) - - - - diff --git a/test/offline/config/jak3/config.jsonc b/test/offline/config/jak3/config.jsonc index 3a3d2cb53c4..e59b3ee5068 100644 --- a/test/offline/config/jak3/config.jsonc +++ b/test/offline/config/jak3/config.jsonc @@ -49,7 +49,9 @@ "update-math-camera", "transform-point-vector!", "transform-point-qword!", - "transform-point-vector-scale!" + "transform-point-vector-scale!", + // dma + "dma-buffer-add-vu-function" ], "skip_compile_states": {}