jak-project/goal_src/engine/ps2/rpc-h.gc
water111 6e0ff4c9d0
[Decompiler] Clean up the output (#245)
* fix parent issue

* fix compiler issue

* update

* add error messages

* fix error

* fix array access, temporary

* more clean

* fix

* rename arg variables better

* fix method name

* fix no return value in decompiler

* many small fixes

* cheat types so it works

* name map

* fix old test'
2021-02-09 20:59:14 -05:00

228 lines
8.1 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
;; name: rpc-h.gc
;; name in dgo: rpc-h
;; dgos: GAME, ENGINE
;; an RPC buffer is a container of elements to send to the IOP.
;; each element is size elt-size, and there are maximum of elt-count elements
;; it is possible to use fewer elements than elt-count.
;; the buffer is 64-byte aligned.
(deftype rpc-buffer (basic)
((elt-size uint32 :offset-assert 4)
(elt-count uint32 :offset-assert 8)
(elt-used uint32 :offset-assert 12)
(busy basic :offset-assert 16) ;; are we being sent currently?
(base pointer :offset-assert 20) ;; 64-byte aligned buffer of elts.
;; I suspect this was 16-byte aligned for DMA purposes.
(data uint8 :dynamic :offset 32)
)
(:methods
(new (symbol type uint uint) rpc-buffer 0)
)
:method-count-assert 9
:size-assert #x20
:flag-assert #x900000020
)
(defmethod new rpc-buffer ((allocation symbol) (type-to-make type) (elt-size uint) (elt-count uint))
"Create a new rpc-buffer with room for elt-count elements of elt-size.
The element array is 64-byte aligned."
;; we make room for a buffer of size elt-size * elt-count that is _64 byte_ aligned.
(let ((obj (object-new allocation type-to-make (the int (+ (-> type-to-make size) 63 (* elt-size elt-count))))))
(set! (-> obj elt-size) elt-size)
(set! (-> obj elt-count) elt-count)
(set! (-> obj elt-used) 0)
(set! (-> obj busy) '#f)
;(set! (-> obj base) (logand -64 (+ (the uint obj) 28 63)))
;; base is the 64-byte aligned buffer.
(set! (-> obj base) (the pointer (logand -64 (+ (the uint (-> obj data)) 63))))
obj
)
)
;; An RPC buffer pair is a pair of two buffers that implement double buffering.
;; The "current" buffer is the one being loaded on the EE.
;; The other is referred to as the active buffer.
;; This also supports receiving data, though it just gives you a plain pointer.
(deftype rpc-buffer-pair (basic)
((buffer rpc-buffer 2 :offset-assert 4) ;; the two buffers
(current rpc-buffer :offset-assert 12) ;; the buffer being loaded
(last-recv-buffer pointer :offset-assert 16) ;; the last reply
(rpc-port int32 :offset-assert 20) ;; the RPC port number
)
:method-count-assert 15
:size-assert #x18
:flag-assert #xf00000018
(:methods
(new (symbol type uint uint int) rpc-buffer-pair 0)
(call (rpc-buffer-pair uint pointer uint) int 9)
(add-element (rpc-buffer-pair) pointer 10)
(decrement-elt-used (rpc-buffer-pair) int 11)
(sync (rpc-buffer-pair symbol) int 12)
(check-busy (rpc-buffer-pair) symbol 13)
(pop-last-received (rpc-buffer-pair) pointer 14)
)
)
(defmethod new rpc-buffer-pair ((allocation symbol) (type-to-make type) (elt-size uint) (elt-count uint) (rpc-port int))
"Create a new rpc-buffer-pair"
(let ((obj (object-new allocation type-to-make)))
(set! (-> obj buffer 0) (new 'global 'rpc-buffer elt-size elt-count))
(set! (-> obj buffer 1) (new 'global 'rpc-buffer elt-size elt-count))
(set! (-> obj current) (-> obj buffer 0))
(set! (-> obj last-recv-buffer) (the pointer '#f))
(set! (-> obj rpc-port) rpc-port)
obj
)
)
;; method 12
(defmethod sync rpc-buffer-pair ((obj rpc-buffer-pair) (print-stall-warning symbol))
"Wait for the in progress RPC to complete."
(let ((active-buffer (if (= (-> obj buffer 0) (-> obj current))
(-> obj buffer 1)
(-> obj buffer 0))
)
)
(when (-> active-buffer busy)
;; the flag is set, meaning we should check.
(cond
((!= 0 (rpc-busy? (-> obj rpc-port)))
;; we're busy
(if print-stall-warning
(format 0 "STALL: waiting for IOP on RPC port #~D~%" (-> obj rpc-port))
)
(while (!= 0 (rpc-busy? (-> obj rpc-port)))
;; real game has a bunch of nops
(+ 1 2 3)
)
)
(else
;; not actually busy, clear the flag!
(set! (-> active-buffer busy) '#f)
(set! (-> active-buffer elt-used) 0)
)
)
)
)
0
)
;; method 13
(defmethod check-busy rpc-buffer-pair ((obj rpc-buffer-pair))
"Is the currently running RPC still busy?"
(let ((active-buffer (if (= (-> obj buffer 0) (-> obj current))
(-> obj buffer 1)
(-> obj buffer 0)
)))
(when (-> active-buffer busy)
(if (!= 0 (rpc-busy? (-> obj rpc-port)))
(return-from #f '#t)
)
(set! (-> active-buffer busy) '#f)
(set! (-> active-buffer elt-count) 0)
)
)
'#f
)
;; method 9
(defmethod call rpc-buffer-pair ((obj rpc-buffer-pair) (fno uint) (recv-buff pointer) (recv-size uint))
"Call an RPC. This is an async RPC. Use check-busy or sync to see if it's done."
(when (!= 0 (-> obj current elt-used))
;; when we have used elements
(format 0 "call rpc-buffer-pair with ~D elts~%" (-> obj current elt-used))
;; make sure the previous buffer is done
(let ((active-buffer (if (= (-> obj buffer 0) (-> obj current))
(-> obj buffer 1)
(-> obj buffer 0))))
(when (-> active-buffer busy)
;; we think the active buffer may be busy.
;; first lets just do a simple check
(cond
((!= 0 (rpc-busy? (-> obj rpc-port)))
;; busy! print an error and stall!
(format 0 "STALL: waiting for IOP on RPC port #~D~%" (-> obj rpc-port))
(while (!= 0 (rpc-busy? (-> obj rpc-port)))
(+ 1 2 3)
)
)
(else
;; not busy.
(set! (-> active-buffer busy) '#f)
(set! (-> active-buffer elt-used) 0)
)
)
)
;; now we've cleared the last RPC call, we can do another
(let ((current-buffer (-> obj current)))
;; rpc_channel, fno, async, send_buff, send_size, recv_buff, recv_size
(format 0 "recv-size is ~D~%" recv-size)
(rpc-call (-> obj rpc-port)
fno
(the uint 1)
(the uint (-> current-buffer base))
(the int (* (-> current-buffer elt-used) (-> current-buffer elt-size)))
(the uint recv-buff)
(the int recv-size)
)
(set! (-> current-buffer busy) '#t)
(set! (-> obj last-recv-buffer) recv-buff)
(set! (-> obj current) active-buffer)
)
)
)
0
)
;; method 14
(defmethod pop-last-received rpc-buffer-pair ((obj rpc-buffer-pair))
(let ((result (-> obj last-recv-buffer)))
(set! (-> obj last-recv-buffer) (the pointer '#f))
result
)
)
;; method 10
(defmethod add-element rpc-buffer-pair ((obj rpc-buffer-pair))
"Add an element, and return a pointer to the element.
If we are out of elements, flush by doing an RPC call.
DANGER: this uses all arguments of 0. If you want something else, flush it yourself.
If we're RPC 0 and we do this auto-flush, print a warning.
"
(let ((current-buffer (-> obj current)))
(when (= (-> current-buffer elt-count) (-> current-buffer elt-used))
;; oops, we're full.
(if (= 0 (-> obj rpc-port))
;; if we're RPC 0, this is evidently a situation to warn about.
(format 0 "WARNING: too many sound commands queued~%")
)
;; otherwise we just flush
;; seems kinda dangerous. these could be the wrong parameters...
(call obj (the uint 0) (the pointer 0) (the uint 0))
;; update the current-buffer.
(set! current-buffer (-> obj current))
)
(let ((result (&+ (-> current-buffer base) (* (-> current-buffer elt-size) (-> current-buffer elt-used)))))
(+! (-> current-buffer elt-used) 1)
result
)
)
)
;; method 11
(defmethod decrement-elt-used rpc-buffer-pair ((obj rpc-buffer-pair))
"If elt-used > 0, decrease it by one."
(when (> (-> obj current elt-used) 0)
(-! (-> obj current elt-used) 1)
)
0
)