diff --git a/common/goos/Interpreter.cpp b/common/goos/Interpreter.cpp index 4d3bb0e2f4..e2c941085e 100644 --- a/common/goos/Interpreter.cpp +++ b/common/goos/Interpreter.cpp @@ -484,6 +484,12 @@ Object Interpreter::eval_symbol(const Object& sym, const std::shared_ptr& env, + Object* result) { + return try_symbol_lookup(sym, env, result); +} + /*! * Evaluate a pair, either as special form, builtin form, macro application, or lambda application. */ diff --git a/common/goos/Interpreter.h b/common/goos/Interpreter.h index 2d19b4e25e..9aa98d17a2 100644 --- a/common/goos/Interpreter.h +++ b/common/goos/Interpreter.h @@ -23,6 +23,9 @@ class Interpreter { Object intern(const std::string& name); void disable_printfs(); Object eval_symbol(const Object& sym, const std::shared_ptr& env); + bool eval_symbol(const Object& sym, + const std::shared_ptr& env, + Object* result); Arguments get_args(const Object& form, const Object& rest, const ArgumentSpec& spec); void set_args_in_env(const Object& form, const Arguments& args, diff --git a/common/goos/Object.cpp b/common/goos/Object.cpp index 9700e28349..1c6bb05bac 100644 --- a/common/goos/Object.cpp +++ b/common/goos/Object.cpp @@ -40,6 +40,7 @@ #include "Object.h" #include "common/util/FileUtil.h" +#include "third-party/fmt/core.h" namespace goos { @@ -90,6 +91,18 @@ std::string fixed_to_string(FloatType x) { return {buff}; } +/*! + * Special case to print an integer + */ +template <> +std::string fixed_to_string(IntType x) { + if (x > 10000) { + return fmt::format("#x{:x}", x); + } else { + return fmt::format("{}", x); + } +} + /*! * Special case to print a character and escape the weird ones. */ diff --git a/common/goos/Object.h b/common/goos/Object.h index 5b00c1850f..3aba2221e4 100644 --- a/common/goos/Object.h +++ b/common/goos/Object.h @@ -104,6 +104,12 @@ std::string fixed_to_string(FloatType); template <> std::string fixed_to_string(char); +/*! + * Special case to print integer + */ +template <> +std::string fixed_to_string(IntType); + /*! * Common implementation for a fixed object */ diff --git a/common/type_system/TypeSystem.cpp b/common/type_system/TypeSystem.cpp index be78c10215..a54a26af66 100644 --- a/common/type_system/TypeSystem.cpp +++ b/common/type_system/TypeSystem.cpp @@ -779,9 +779,10 @@ void TypeSystem::add_builtin_types() { // VU FUNCTION // don't inherit - add_field_to_type(vu_function_type, "length", make_typespec("int32")); // todo integer type - add_field_to_type(vu_function_type, "origin", make_typespec("pointer")); // todo sign extend? - add_field_to_type(vu_function_type, "qlength", make_typespec("int32")); // todo integer type + add_field_to_type(vu_function_type, "length", make_typespec("int32")); // todo integer type + add_field_to_type(vu_function_type, "origin", make_typespec("int32")); // todo sign extend? + add_field_to_type(vu_function_type, "qlength", make_typespec("int32")); // todo integer type + add_field_to_type(vu_function_type, "data", make_typespec("uint8"), false, true); // link block builtin_structure_inherit(link_block_type); diff --git a/decompiler/IR2/AtomicOp.cpp b/decompiler/IR2/AtomicOp.cpp index 953c78e2f9..fb1a2d9c35 100644 --- a/decompiler/IR2/AtomicOp.cpp +++ b/decompiler/IR2/AtomicOp.cpp @@ -128,7 +128,7 @@ goos::Object SimpleAtom::to_form(const std::vector& labels, con case Kind::VARIABLE: return m_variable.to_form(env); case Kind::INTEGER_CONSTANT: - return pretty_print::to_symbol(std::to_string(m_int)); + return goos::Object::make_integer(m_int); case Kind::SYMBOL_PTR: return pretty_print::to_symbol(fmt::format("'{}", m_string)); case Kind::SYMBOL_VAL: diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index a671a88f2b..4128ece7dd 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -1335,13 +1335,6 @@ void FunctionCallElement::update_from_stack(const Env& env, // throw std::runtime_error("Failed to match new method: " + // temp_form->to_string(env)); } - } else { - auto ti = env.dts->ts.lookup_type(type_1); - auto is_basic = dynamic_cast(ti); - if (!is_basic) { - throw std::runtime_error( - fmt::format("Method call detected, not yet implemented {} {}\n", name, type_1)); - } } } } @@ -1815,6 +1808,15 @@ FormElement* ConditionElement::make_generic(const Env&, casted); } + case IR2_Condition::Kind::GREATER_THAN_ZERO_UNSIGNED: { + auto casted = make_cast(source_forms, types, TypeSpec("uint"), pool); + auto zero = pool.alloc_single_element_form( + nullptr, SimpleAtom::make_int_constant(0)); + casted.push_back(zero); + return pool.alloc_element(GenericOperator::make_fixed(FixedOperatorKind::GT), + casted); + } + case IR2_Condition::Kind::GREATER_THAN_ZERO_SIGNED: { auto casted = make_cast(source_forms, types, TypeSpec("int"), pool); auto zero = pool.alloc_single_element_form( @@ -1984,7 +1986,8 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack) auto as_special = dynamic_cast(m_op); if (as_special) { if (as_special->kind() == SpecialOp::Kind::NOP || - as_special->kind() == SpecialOp::Kind::BREAK) { + as_special->kind() == SpecialOp::Kind::BREAK || + as_special->kind() == SpecialOp::Kind::CRASH) { stack.push_form_element(this, true); return; } diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index c336c8cd1d..a1d78f3083 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -60,6 +60,9 @@ (define-extern file-stream-length (function file-stream int)) (define-extern file-stream-read (function file-stream pointer int int)) +(define-extern dma-sync (function pointer int int int)) +(define-extern flush-cache (function int none)) + ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; GCOMMON ;;;;;;;;;;;;;;;;;;; @@ -1567,14 +1570,20 @@ ;;(define-extern sound-id object) ;; unknown type (deftype sound-id (uint32) () + (:methods + (dummy-9 () none 9) + ) + :flag-assert #xa00000004 ) (deftype sound-bank-id (uint32) () + :flag-assert #x900000004 ) (deftype sound-name (uint128) () + :flag-assert #x900000010 ) ;;(define-extern sound-play-parms object) ;; unknown type ;;(define-extern sound-rpc-load-bank object) ;; unknown type @@ -2022,33 +2031,51 @@ (define-extern stopwatch-elapsed-ticks (function stopwatch uint)) (define-extern stopwatch-elapsed-seconds (function stopwatch float)) -;;;;;;;;;;;;; -;; vif-h -;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; VIF-H ;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; ; ;; vif-h (deftype vif-stat (uint32) - () + ((vps uint8 :offset 0 :size 2) + (vew uint8 :offset 2 :size 1) + (mrk uint8 :offset 6 :size 1) + (vss uint8 :offset 8 :size 1) + (vfs uint8 :offset 9 :size 1) + (vis uint8 :offset 10 :size 1) + (int uint8 :offset 11 :size 1) + (er0 uint8 :offset 12 :size 1) + (er1 uint8 :offset 13 :size 1) + (fqc uint8 :offset 24 :size 4) + ) + :method-count-assert 9 :size-assert #x4 :flag-assert #x900000004 - ;; likely a bitfield type ) (deftype vif-fbrst (uint32) - () + ((rst uint8 :offset 0 :size 1) + (fbk uint8 :offset 1 :size 1) + (stp uint8 :offset 2 :size 1) + (stc uint8 :offset 3 :size 1) + ) :method-count-assert 9 :size-assert #x4 :flag-assert #x900000004 - ;; likely a bitfield type ) + (deftype vif-err (uint32) - () + ((mii uint8 :offset 0 :size 1) + (me0 uint8 :offset 1 :size 1) ;; PS2 hardware bug, must set this to 1 for correct operation. + (me1 uint8 :offset 2 :size 1) + ) :method-count-assert 9 :size-assert #x4 :flag-assert #x900000004 - ;; likely a bitfield type ) ;; vif-h @@ -2081,13 +2108,31 @@ :size-assert #x174 :flag-assert #x900000174 ) + +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; DMA-H ;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; + +(deftype dma-sqwc (uint32) + () + :flag-assert #x900000004 + ) + ; ;; dma-h (deftype dma-chcr (uint32) - () + ((dir uint8 :offset 0 :size 1) ;; 1 - from memory + (mod uint8 :offset 2 :size 2) ;; normal, chain, interleave + (asp uint8 :offset 4 :size 2) ;; none, 1, 2 + (tte uint8 :offset 6 :size 1) ;; transfer tag (sc only) + (tie uint8 :offset 7 :size 1) ;; tag interrupt + (str uint8 :offset 8 :size 1) ;; start! + (tag uint16 :offset 16) + ) :method-count-assert 9 :size-assert #x4 :flag-assert #x900000004 - ;; likely a bitfield type ) (deftype dma-ctrl (uint32) @@ -2099,7 +2144,7 @@ ) (deftype dma-bank (structure) - ((chcr uint32 :offset 0) + ((chcr dma-chcr :offset 0) (madr uint32 :offset 16) (qwc uint32 :offset 32) ) @@ -2134,10 +2179,10 @@ ) (deftype dma-bank-control (structure) - ((ctrl uint32 :offset 0) + ((ctrl dma-ctrl :offset 0) (stat uint32 :offset 16) (pcr uint32 :offset 32) - (sqwc uint32 :offset 48) + (sqwc dma-sqwc :offset 48) (rbsr uint32 :offset 64) (rbor uint32 :offset 80) (stadr uint32 :offset 96) @@ -2162,33 +2207,74 @@ ; ;; dma-h (deftype dma-tag (uint64) - () + ((qwc uint16 :offset 0) ;; quadword count + (pce uint8 :offset 26 :size 2) ;; priority (source mode) + (id uint8 :offset 28 :size 3) ;; ID (what the tag means) + (irq uint8 :offset 31 :size 1) ;; interrupt at the end? + (addr uint32 :offset 32 :size 31) ;; address (31 bits) + (spr uint8 :offset 63 :size 1) ;; spr or not flag. + ) :method-count-assert 9 :size-assert #x8 :flag-assert #x900000008 - ;; likely a bitfield type ) - ; ;; dma-h (deftype dma-bucket (structure) - ((tag uint64 :offset-assert 0) - (last uint32 :offset-assert 8) - (dummy uint32 :offset-assert 12) - (next uint32 :offset 4) + ((tag dma-tag :offset-assert 0) ;; the DMA tag to transfer the bucket's data + (last (pointer uint64) :offset-assert 8) ;; the last tag of this bucket. + (dummy uint32 :offset-assert 12) ;; empty space. + (next uint32 :offset 4) ;; this overlaps with the addr bit-field of the dma-tag ) :method-count-assert 9 :size-assert #x10 :flag-assert #x900000010 ) -; ;; dma-h -; (deftype vif-tag (uint32) -; () -; :method-count-assert 9 -; :size-assert #x4 -; :flag-assert #x900000004 -; ;; likely a bitfield type -; ) + +;; dma-h + +(deftype vif-tag (uint32) + ((imm uint16 :offset 0 :size 16) + (num uint8 :offset 16 :size 8) + (cmd uint8 :offset 24 :size 8) + (irq uint8 :offset 31 :size 1) ;;? + (msk uint8 :offset 15 :size 1) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) +(deftype dma-enable (uint32) + () + :flag-assert #x900000004 + ) + + +(deftype vu-stat (uint64) + () + :flag-assert #x900000008 + ) + +(deftype vif-mask (uint32) + () + :flag-assert #x900000004 + ) + +(deftype vif-stcycl-imm (uint16) + () + :flag-assert #x900000002 + ) + +(deftype vif-unpack-imm (uint16) + () + :flag-assert #x900000002 + ) + +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; VIDEO-H ;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; ; ;; video-h (deftype video-parms (structure) @@ -2214,6 +2300,12 @@ :flag-assert #x900000048 ) +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; VU1-USER-H ;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; + ;; vu1-user-h (deftype dma-foreground-sink (basic) ((bucket int32 :offset-assert 4) @@ -2244,25 +2336,118 @@ :flag-assert #x900000014 ) +(deftype dma-foreground-sink (basic) + ((bucket int32 :offset-assert 4) ;; not sure if this is a bucket index or pointer? + (foreground-texture-page int8 :offset-assert 8) ;; ? + (foreground-texture-level int8 :offset-assert 9) ;; ? + (foreground-output-bucket int8 :offset-assert 10) ;; ? + ) + :method-count-assert 9 + :size-assert #xb + :flag-assert #x90000000b + ) + (deftype dma-foreground-sink-group (basic) - ((sink basic 3 :offset-assert 4) - (merc-sink basic :offset 4) - (generic-sink basic :offset 8) - (level basic :offset 16) + ((sink dma-foreground-sink 3 :offset-assert 4) + (merc-sink dma-foreground-sink :offset 4) + (generic-sink generic-dma-foreground-sink :offset 8) + (level basic :offset-assert 16) ) :method-count-assert 9 :size-assert #x14 :flag-assert #x900000014 ) -;;;;;;;;;;;;;;; -;; dma-buffer -;;;;;;;;;;;;;;; + +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; DMA ;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; + +(define-extern reset-path (function none)) +(define-extern reset-graph (function int int int int 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 vif-stat object) ;; unknown type +;;(define-extern vif-fbrst object) ;; unknown type +;;(define-extern vif-err object) ;; unknown type +;;(define-extern vif-bank object) ;; unknown type +(define-extern dma-count-until-done (function dma-bank (pointer int32) int)) +;;(define-extern vif-tag object) ;; unknown type +(define-extern dma-send-no-scratch (function dma-bank uint32 uint32 none)) +;;(define-extern dma-tag object) ;; unknown type +;;(define-extern dma-chcr object) ;; unknown type +;;(define-extern dma-bank-spr object) ;; unknown type +;;(define-extern dma-bucket object) ;; unknown type +(define-extern dma-sync-with-count (function dma-bank (pointer int32) int)) +;;(define-extern vu-code-block object) ;; unknown type +(define-extern dma-sync-fast (function dma-bank none)) +;;(define-extern vif-mask object) ;; unknown type +;;(define-extern dma-bank-control object) ;; unknown type +;;(define-extern vif-unpack-imm object) ;; unknown type +;;(define-extern dma-ctrl object) ;; unknown type +;;(define-extern dma-enable object) ;; unknown type +;;(define-extern vu-stat object) ;; unknown type +;;(define-extern dma-bank-source object) ;; unknown type +;;(define-extern dma-bank-vif object) ;; unknown type +;;(define-extern dma-sqwc object) ;; unknown type +;;(define-extern vif-stcycl-imm object) ;; unknown type +;;(define-extern dma-bank object) ;; unknown type +;;(define-extern flush-cache object) ;; unknown type +;;(define-extern *video-parms* object) ;; unknown type +;;(define-extern video-parms object) ;; unknown type +;;(define-extern generic-bucket-state object) ;; unknown type +;;(define-extern *vu1-enable-user-menu* object) ;; unknown type +(define-extern dma-foreground-sink type) +(define-extern dma-foreground-sink-group type) +;;(define-extern *vu1-enable-user* object) ;; unknown type +(define-extern generic-dma-foreground-sink type) + + +(define-extern symlink3 (function none)) + + + + +(define-extern dma-sync-hang (function dma-bank none)) +(define-extern symlink2 (function none)) + + + +(define-extern dma-send (function dma-bank uint uint none)) + +(define-extern *video-reset-parm* int) + + + +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; DMA-BUFFER ;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; (deftype dma-packet (structure) - ((dma uint64 :offset-assert 0) - (vif0 uint32 :offset-assert 8) - (vif1 uint32 :offset-assert 12) + ((dma dma-tag :offset-assert 0) + (vif0 vif-tag :offset-assert 8) + (vif1 vif-tag :offset-assert 12) ;; doesn't have to be a vif tag. (quad uint128 :offset 0) ) :method-count-assert 9 @@ -2289,32 +2474,64 @@ (deftype dma-buffer (basic) ((allocated-length int32 :offset-assert 4) - (base uint32 :offset-assert 8) + (base pointer :offset-assert 8) (end uint32 :offset-assert 12) - (data uint64 1 :offset-assert 16) ;; hmmm, seems wrong + (data uint64 1 :offset-assert 16) ;; weird, I guess this aligns the data? + (data-buffer uint8 :dynamic :offset 16) + ) + (:methods + (new (symbol type int) _type_ 0) ) :method-count-assert 9 :size-assert #x18 :flag-assert #x900000018 ) +;;(define-extern reset-path object) ;; unknown type +;;(define-extern reset-graph object) ;; unknown type +;;(define-extern dma-sync object) ;; unknown type +;;(define-extern dma-packet-array object) ;; unknown type +(define-extern dma-buffer-inplace-new (function dma-buffer int dma-buffer)) +(define-extern dma-buffer-length (function dma-buffer uint)) +(define-extern dma-buffer-free (function dma-buffer int)) + +;;(define-extern dma-gif-packet object) ;; unknown type + +(define-extern dma-buffer-add-vu-function (function dma-buffer vu-function int symbol)) +;;(define-extern dma-packet object) ;; unknown type +;;(define-extern dma-buffer object) ;; unknown type +(define-extern dma-buffer-send-chain (function dma-bank-source dma-buffer none)) +(define-extern dma-buffer-send (function dma-bank dma-buffer none)) +(define-extern dma-bucket-insert-tag (function dma-bucket int dma-bucket (pointer uint64) dma-bucket)) +(define-extern dma-buffer-add-buckets (function dma-buffer int none)) +(define-extern dma-buffer-patch-buckets (function dma-bucket int int)) + ;;;;;;;;;;;;;;; ;; dma-disasm ;;;;;;;;;;;;;;; + (deftype vif-disasm-element (structure) ((mask uint32 :offset-assert 0) (tag uint32 :offset-assert 4) (val uint32 :offset-assert 8) (print uint32 :offset-assert 12) - (string1 basic :offset-assert 16) - (string2 basic :offset-assert 20) + (string1 string :offset-assert 16) + (string2 string :offset-assert 20) ) :method-count-assert 9 :size-assert #x18 :flag-assert #x900000018 ) +(define-extern *vif-disasm-table* (array vif-disasm-element)) ;; unknown type +(define-extern disasm-vif-tag function) +(define-extern disasm-dma-tag function) +(define-extern disasm-vif-details (function symbol (pointer uint8) int int int)) +(define-extern vif-disasm-element type) +;;(define-extern *dma-disasm* object) ;; unknown type +(define-extern disasm-dma-list function) + ;;;;;;;;;;;;;;; ;; pad ;;;;;;;;;;;;;;; @@ -31921,84 +32138,9 @@ (define-extern vector-circle-tangent-new function) -; -;;(define-extern vif-stat object) ;; unknown type -;;(define-extern vif-fbrst object) ;; unknown type -;;(define-extern vif-err object) ;; unknown type -;;(define-extern vif-bank object) ;; unknown type -(define-extern dma-count-until-done function) -;;(define-extern vif-tag object) ;; unknown type -(define-extern dma-send-no-scratch function) -;;(define-extern dma-tag object) ;; unknown type -;;(define-extern dma-chcr object) ;; unknown type -;;(define-extern dma-bank-spr object) ;; unknown type -;;(define-extern dma-bucket object) ;; unknown type -(define-extern dma-sync-with-count function) -;;(define-extern vu-code-block object) ;; unknown type -(define-extern dma-sync-fast function) -;;(define-extern vif-mask object) ;; unknown type -;;(define-extern dma-bank-control object) ;; unknown type -;;(define-extern vif-unpack-imm object) ;; unknown type -;;(define-extern dma-ctrl object) ;; unknown type -;;(define-extern dma-enable object) ;; unknown type -;;(define-extern vu-stat object) ;; unknown type -;;(define-extern dma-bank-source object) ;; unknown type -;;(define-extern dma-bank-vif object) ;; unknown type -;;(define-extern dma-sqwc object) ;; unknown type -;;(define-extern vif-stcycl-imm object) ;; unknown type -;;(define-extern dma-bank object) ;; unknown type -;;(define-extern flush-cache object) ;; unknown type -;;(define-extern *video-parms* object) ;; unknown type -;;(define-extern video-parms object) ;; unknown type -;;(define-extern generic-bucket-state object) ;; unknown type -;;(define-extern *vu1-enable-user-menu* object) ;; unknown type -(define-extern dma-foreground-sink type) -(define-extern dma-foreground-sink-group type) -;;(define-extern *vu1-enable-user* object) ;; unknown type -(define-extern generic-dma-foreground-sink type) -(define-extern reset-vif1-path function) -(define-extern dump-vu1-range function) -(define-extern symlink3 function) -(define-extern dma-sync-crash function) -(define-extern clear-vu0-mem function) -(define-extern dump-vu1-mem function) -(define-extern dma-send-from-spr function) -(define-extern dma-send-to-spr function) -(define-extern dma-sync-hang function) -(define-extern symlink2 function) -(define-extern ultimate-memcpy function) -(define-extern dma-send-to-spr-no-flush function) -(define-extern dma-initialize function) -(define-extern dma-send function) -(define-extern dma-send-chain-no-flush function) -(define-extern clear-vu1-mem function) -(define-extern dma-send-from-spr-no-flush function) -;;(define-extern *video-reset-parm* object) ;; unknown type -(define-extern dma-send-chain function) -(define-extern dma-send-chain-no-tte function) -;;(define-extern reset-path object) ;; unknown type -;;(define-extern reset-graph object) ;; unknown type -;;(define-extern dma-sync object) ;; unknown type -;;(define-extern dma-packet-array object) ;; unknown type -(define-extern dma-buffer-inplace-new function) -(define-extern dma-buffer-length function) -;;(define-extern dma-gif-packet object) ;; unknown type -(define-extern dma-buffer-free function) -(define-extern dma-buffer-add-vu-function function) -;;(define-extern dma-packet object) ;; unknown type -;;(define-extern dma-buffer object) ;; unknown type -(define-extern dma-buffer-send-chain function) -(define-extern dma-buffer-send function) -(define-extern dma-bucket-insert-tag function) -(define-extern dma-buffer-add-buckets function) -(define-extern dma-buffer-patch-buckets function) -;;(define-extern *vif-disasm-table* object) ;; unknown type -(define-extern disasm-vif-tag function) -(define-extern disasm-dma-tag function) -(define-extern disasm-vif-details function) -(define-extern vif-disasm-element type) -;;(define-extern *dma-disasm* object) ;; unknown type -(define-extern disasm-dma-list function) + + + ;;(define-extern error object) ;; unknown type ;;(define-extern details object) ;; unknown type (define-extern cpad-set-buzz! function) diff --git a/decompiler/config/jak1_ntsc_black_label/type_hints.jsonc b/decompiler/config/jak1_ntsc_black_label/type_hints.jsonc index e8a82c49e0..334f0ac6ee 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_hints.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_hints.jsonc @@ -32,7 +32,7 @@ ], "(method 2 handle)":[ - [10, ["a2", "(pointer process)"]], + [10, ["a2", "(pointer process)"]], [11, ["a3", "process"]], [12, ["v1", "int"]], [16, ["gp", "int"]] @@ -77,8 +77,8 @@ "(method 14 dead-pool)":[ // bug in game! - [24, ["v1", "(pointer process-tree)"]], - [30, ["s4", "(pointer process-tree)"]] + [24, ["v1", "(pointer process-tree)"]], + [30, ["s4", "(pointer process-tree)"]] ], "throw":[ @@ -108,16 +108,76 @@ ], "string-cat-to-last-char":[ - [3, ["s5", "(pointer uint8)"]], - [4, ["s5", "string"]] + [3, ["s5", "(pointer uint8)"]], + [4, ["s5", "string"]] ], "string-strip-trailing-whitespace!":[ - [15, ["v1", "(pointer uint8)"]] + [15, ["v1", "(pointer uint8)"]] ], "(anon-function 15 hud)":[ - [0, ["s6", "hud"]] - ] + [0, ["s6", "hud"]] + ], + + "dma-send-to-spr":[ + [5, ["s5", "dma-bank-spr"]]], + "dma-send-to-spr-no-flush":[ + [5, ["s5", "dma-bank-spr"]]], + "dma-send-from-spr":[ + [5, ["s5", "dma-bank-spr"]]], + "dma-send-from-spr-no-flush":[ + [5, ["s5", "dma-bank-spr"]]], + "dma-initialize":[ + [1, ["v1", "vif-bank"]], + [6, ["a0", "vif-bank"]], + [8, ["v1", "vif-bank"]], + [13, ["a0", "vif-bank"]]], + + "clear-vu0-mem":[ + [1, ["v1", "(pointer uint32)"]] + ], + "clear-vu1-mem":[ + [1, ["v1", "(pointer uint32)"]] + ], + + "dump-vu1-mem":[ + [1, ["gp", "(pointer uint32)"]]], + + "dump-vu1-range":[ + [3, ["s4", "(pointer uint32)"]]], + + "ultimate-memcpy":[ + [5, ["s3", "dma-bank-spr"],["s4", "dma-bank-spr"]] + ], + + "dma-buffer-add-vu-function":[ + [13, ["v1", "uint"]], + [23, ["t2", "(pointer uint32)"]] + ], + + "dma-buffer-add-buckets":[ + [1, ["v0", "dma-bucket"]], + [5, ["v1", "uint"]], + [6, ["t0", "uint"]], + [9, ["v1", "dma-bucket"]], + [11, ["v1", "uint"]], + [12, ["v1", "dma-bucket"]] + ], + + "dma-buffer-patch-buckets":[ + [7, ["a0", "uint"]], + [11, ["a0", "dma-bucket"]], + [14, ["a0", "uint"]], + [15, ["a0", "dma-bucket"]] + ], + + "dma-bucket-insert-tag":[ + [1, ["a0", "uint"]], + [2, ["v1", "dma-bucket"]] + ] + + + } \ No newline at end of file diff --git a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc index e1151c9667..a5d27ce8d0 100644 --- a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc @@ -380,6 +380,54 @@ }, "ease-in-out":{ "args":["total", "progress"] + }, + "dma-send-to-spr":{ + "args":["sadr", "madr", "qwc", "sync"] + }, + "dma-send-to-spr-no-flush":{ + "args":["sadr", "madr", "qwc", "sync"] + }, + "dma-send-from-spr":{ + "args":["madr", "sadr", "qwc", "sync"] + }, + "dma-send-from-spr-no-flush":{ + "args":["madr", "sadr", "qwc", "sync"] + }, + "dump-vu1-range":{ + "args":["start", "total-count"] + }, + "ultimate-memcpy":{ + "args":["dst", "src", "size-bytes"], + "vars":{"s2-0":"qwc-remaining", + "s1-0":"qwc-transferred-now", + "s4-0":"spr-to-bank", + "s3-0":"spr-from-bank"} + }, + + "dma-buffer-add-vu-function":{ + "args":["dma-buf", "vu-func"], + "vars":{"t1-1":"dma-buf-2", "v1-0":"func-ptr", "a3-0":"qlen", "a1-1":"origin", "t0-1":"qwc-now", + "t2-0":"buf-ptr"} + }, + + "dma-buffer-add-buckets":{ + "args":["dma-buf", "count"], + "vars":{"a2-0":"i", "v1-0":"current-bucket"} + }, + + "dma-buffer-patch-buckets":{ + "args":["bucket", "count"], + "vars":{"v1-1":"i"} + }, + + "dma-bucket-insert-tag":{ + "args":["base", "idx", "tag-start", "tag-end"] + }, + + "disasm-vif-details":{ + "args":["stream", "data", "kind", "count"], + "vars":{"s4-0":"count2", "s3-0":"data-ptr", "s2-0":"i"} } + } \ No newline at end of file diff --git a/doc/code_status.md b/doc/code_status.md index 966634dc3c..650045f02c 100644 --- a/doc/code_status.md +++ b/doc/code_status.md @@ -68,20 +68,48 @@ ## `trigonometry-h`: **Done** - Empty -## `transformq-h`: +## `transformq-h`: waiting on stack stuff - Needs stack stuff -## `bounding-box`: +## `bounding-box`: asm -## `matrix`: +## `matrix`: asm -## `transform`: +## `transform`: asm -## `quaternion`: +## `quaternion`: asm -## `euler`: +## `euler`: asm -## `geometry`: +## `geometry`: asm ## `trigonometry`: **Done** - `sincos!` and `sincos-rad!` have a bug where cosine is slightly off + +## `gsound-h`: **Done** + +## `timer-h`: **Done** +- `timer-init` removed for PC port. + +## `timer`: Decompiled, probably needs porting +- Has functions for accessing PS2 timers, needs to be ported to PC. All the logic for stopwatches etc is decopmiled, just the timer reads/writes need to be modified. + +## `vif-h`: **Done** + +## `dma-h`: **Done** +- DMA sync disabled by default. + +## `video-h`: **Done** + +## `vu1-user-h`: **Done** + +## `dma`: **Done** +- `dma-initialize` disabled on PC. +- Plan is to modify things at a higher level than this for the PC graphics system, most of these functions are non-functional on the PC. +- `ultimate-memcpy` may need to be modified, or we can just swap out code to use the non-`ultimate` version of `memcpy`. + +## `dma-buffer`: **Done** +- The sends won't work on PC, but it should let you build the buffer... + +## `dma-bucket`: **Done** +- Could clean up some bitfield access, should probably add some features to the compiler to help here. \ No newline at end of file diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index f33b013e12..10b1c680e6 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -36,6 +36,8 @@ set(RUNTIME_SOURCE system/Deci2Server.cpp sce/libcdvd_ee.cpp sce/libscf.cpp + sce/libdma.cpp + sce/libgraph.cpp sce/deci2.cpp sce/sif_ee.cpp sce/iop.cpp diff --git a/game/kernel/klink.cpp b/game/kernel/klink.cpp index a767d48bc1..14ce743fab 100644 --- a/game/kernel/klink.cpp +++ b/game/kernel/klink.cpp @@ -878,7 +878,7 @@ uint64_t link_resume() { */ void* ultimate_memcpy(void* dst, void* src, uint32_t size) { // only possible if alignment is good. - if (!(u64(dst) & 0xf) && !(u64(src) & 0xf) && !(u64(size) & 0xf)) { + if (!(u64(dst) & 0xf) && !(u64(src) & 0xf) && !(u64(size) & 0xf) && size > 0xfff) { if (!gfunc_774.offset) { // GOAL function is unknown, lets see if its loaded: auto sym = find_symbol_from_c("ultimate-memcpy"); @@ -887,7 +887,7 @@ void* ultimate_memcpy(void* dst, void* src, uint32_t size) { } gfunc_774.offset = sym->value; } - printf("calling goal um\n"); + printf("calling goal ultimate-memcpy!\n"); return Ptr(call_goal(gfunc_774, make_u8_ptr(dst).offset, make_u8_ptr(src).offset, size, s7.offset, g_ee_main_mem)) .c(); diff --git a/game/kernel/kmachine.cpp b/game/kernel/kmachine.cpp index 29d2090762..0015e0702f 100644 --- a/game/kernel/kmachine.cpp +++ b/game/kernel/kmachine.cpp @@ -24,6 +24,8 @@ #include "game/sce/sif_ee.h" #include "game/sce/libcdvd_ee.h" #include "game/sce/stubs.h" +#include "game/sce/libdma.h" +#include "game/sce/libgraph.h" #include "common/symbols.h" #include "common/log/log.h" using namespace ee; diff --git a/game/main.cpp b/game/main.cpp index 3d21077851..d3227b5c38 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -12,9 +12,9 @@ void setup_logging(bool verbose) { lg::set_file(file_util::get_file_path({"log/game.txt"})); if (verbose) { - lg::set_file_level(lg::level::info); - lg::set_stdout_level(lg::level::info); - lg::set_flush_level(lg::level::info); + lg::set_file_level(lg::level::debug); + lg::set_stdout_level(lg::level::debug); + lg::set_flush_level(lg::level::debug); } else { lg::set_file_level(lg::level::warn); lg::set_stdout_level(lg::level::warn); diff --git a/game/sce/libdma.cpp b/game/sce/libdma.cpp new file mode 100644 index 0000000000..c24affb973 --- /dev/null +++ b/game/sce/libdma.cpp @@ -0,0 +1,8 @@ +#include "libdma.h" + +namespace ee { +int sceDmaSync(sceDmaChan*, s32, s32) { + // successful transfer finish, without timeout = 0 + return 0; +} +} // namespace ee \ No newline at end of file diff --git a/game/sce/libdma.h b/game/sce/libdma.h new file mode 100644 index 0000000000..0721e8bb92 --- /dev/null +++ b/game/sce/libdma.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common/common_types.h" + +namespace ee { +struct sceDmaChan {}; + +int sceDmaSync(sceDmaChan* chan, s32 mode, s32 timeout); +} // namespace ee \ No newline at end of file diff --git a/game/sce/libgraph.cpp b/game/sce/libgraph.cpp new file mode 100644 index 0000000000..6d40bb84d7 --- /dev/null +++ b/game/sce/libgraph.cpp @@ -0,0 +1,9 @@ +#include "libgraph.h" +#include "common/log/log.h" + +namespace ee { +void sceGsResetPath() {} +void sceGsResetGraph(int mode, int inter, int omode, int ffmode) { + lg::warn("sceGsResetGraph: mode {} inter {} omode {} fmode {}\n", mode, inter, omode, ffmode); +} +} // namespace ee \ No newline at end of file diff --git a/game/sce/libgraph.h b/game/sce/libgraph.h new file mode 100644 index 0000000000..448387fe92 --- /dev/null +++ b/game/sce/libgraph.h @@ -0,0 +1,6 @@ +#pragma once + +namespace ee { +void sceGsResetPath(); +void sceGsResetGraph(int mode, int inter, int omode, int ffmode); +} // namespace ee \ No newline at end of file diff --git a/game/sce/stubs.cpp b/game/sce/stubs.cpp index 6ea0765463..782875b413 100644 --- a/game/sce/stubs.cpp +++ b/game/sce/stubs.cpp @@ -19,18 +19,10 @@ void sceGsSyncPath() { assert(false); } -void sceGsResetPath() { - assert(false); -} - void sceGsResetGraph() { assert(false); } -void sceDmaSync() { - assert(false); -} - void sceGsPutIMR() { assert(false); } diff --git a/game/sce/stubs.h b/game/sce/stubs.h index 0c4a59b459..86a5bd4492 100644 --- a/game/sce/stubs.h +++ b/game/sce/stubs.h @@ -10,9 +10,6 @@ namespace ee { void sceGsSyncV(); void sceGsSyncPath(); -void sceGsResetPath(); -void sceGsResetGraph(); -void sceDmaSync(); void sceGsPutIMR(); void sceGsGetIMR(); void sceGsExecStoreImage(); diff --git a/goal_src/engine/dma/dma-bucket.gc b/goal_src/engine/dma/dma-bucket.gc index f3309f6f72..fbe911081a 100644 --- a/goal_src/engine/dma/dma-bucket.gc +++ b/goal_src/engine/dma/dma-bucket.gc @@ -5,3 +5,79 @@ ;; name in dgo: dma-bucket ;; dgos: GAME, ENGINE +;; A dma-bucket is a 16 byte thing that lives in the dma-buffer. +;; buckets live consecutively in the dma-buffer, and can mark the start of a DMA chain +;; location anywhere. + +;; The typical process is: +;; - empty buckets are allocated with add-buckets +;; - tags are put somewhere and added to the appropriate bucket with insert-tag, updating last as needed. +;; - buckets are patched to link to each other with dma-buffer-add-buckets. + +;; the idea here is that you can build the buckets in whatever order you want, but the buckets +;; will be DMAd in the bucket allocation order. + +;; Each bucket contains: +;; a tag, (64-bits), to point to the chain of the bucket +;; last, a pointer to the last tag of this bucket, so the bucket can be patched to point to the next. + +(defun dma-buffer-add-buckets ((dma-buf dma-buffer) (count int)) + "Add count buckets to the dma buffer. Each bucket is initialized empty." + (local-vars (current-bucket dma-bucket) (i int)) + ;; grab the first free memory + (set! current-bucket (the dma-bucket (-> dma-buf base))) + (set! i 0) + (while (< i count) + ;; also sets next, which points to the memory after this bucket + (set! (-> current-bucket tag) + (the dma-tag (logior + #x20000000 + (the-as int (shr (shl (+ (the-as uint current-bucket) 16) 33) 1)) + ) + ) + ) + + ;; nothing in the bucket chain, so our last tag is the bucket tag. + (set! (-> current-bucket last) (the (pointer uint64) current-bucket)) + ;; advance to next bucket + (set! current-bucket (&+ current-bucket 16)) + (set! i (+ i 1)) + ) + ;; update base ptr. + (set! (-> dma-buf base) (the pointer current-bucket)) + (none) + ) + +(defun dma-buffer-patch-buckets ((bucket dma-bucket) (count int)) + "Patch last pointers in a sequence of buckets. + Call this after you have added everything to buckets." + (local-vars (i int)) + (when (nonzero? bucket) + (set! i 0) + (while (< i count) + ;; make last tag of this bucket point to the next bucket. + (set! (-> bucket last 0) + (logior (logand (-> bucket last 0) #x80000000ffffffff) + (shr (shl (+ (the-as uint bucket) 16) 33) 1) + ) + ) + ;; clear last, and move on to the next bucket. + (set! (-> bucket last) (the (pointer uint64) 0)) + (set! bucket (&+ bucket 16)) + (set! i (+ i 1)) + ) + ) + (the-as int bucket) + ) + +(defun dma-bucket-insert-tag ((base dma-bucket) (idx int) (tag-start dma-bucket) (tag-end (pointer uint64))) + "Splice in a tag." + (local-vars (bucket dma-bucket)) + ;; seek to bucket we want to splice before. + (set! bucket (&+ base (shl idx 4))) + ;; append to last tag (kind of a hack here with the types) + (set! (-> (the dma-bucket (-> bucket last)) next) (the uint tag-start)) + ;; make prev = end of tag so we can add more. + (set! (-> bucket last) tag-end) + tag-start + ) diff --git a/goal_src/engine/dma/dma-buffer.gc b/goal_src/engine/dma/dma-buffer.gc index d77d0e2434..a71009fbd0 100644 --- a/goal_src/engine/dma/dma-buffer.gc +++ b/goal_src/engine/dma/dma-buffer.gc @@ -5,3 +5,209 @@ ;; name in dgo: dma-buffer ;; dgos: GAME, ENGINE +;; DMA buffers are used per frame to store DMA data. +;; The dma-buffer manages the memory and dma-bucket organizes the stuff within. + +;; The DMA system reads dma-tags. A common trick is to set the dma in tte mode, which transfers +;; the upper 64-bits of the 128-bit "packet" to the VIF, and you can put your vifcode there: + +;; Ex: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 32-bit vifcode ;; 32-bit vifcode ;; 64-bit dma-tag ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; in this case, the vifcodes will be sent to the vif, if +;; the dma transfer has tte set. +;; note that the second vifcode can also hold other stuff depending on the mode. + + +;; first quadword of a DMA with vif packet +(deftype dma-packet (structure) + ((dma dma-tag :offset-assert 0) + (vif0 vif-tag :offset-assert 8) + (vif1 vif-tag :offset-assert 12) ;; doesn't have to be a vif tag. + (quad uint128 :offset 0) + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +;; seems to be unused? +(deftype dma-packet-array (inline-array-class) + () + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) +(set! (-> dma-packet-array heap-base) 16) + +;; For doing a dma -> vif -> gif (path 2) transfer. +(deftype dma-gif-packet (structure) + ((dma-vif dma-packet :inline :offset-assert 0) + (gif uint64 2 :offset-assert 16) ;; guess + (quad uint128 2 :offset 0) + ) + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +;; dma-buffer holds per-frame data for dma. +;; the allocated-length is in bytes. +;; the base points to the first unused memory in the buffer +;; it is a dynamically sized type. +(deftype dma-buffer (basic) + ((allocated-length int32 :offset-assert 4) + (base pointer :offset-assert 8) + (end uint32 :offset-assert 12) + (data uint64 1 :offset-assert 16) ;; weird, I guess this aligns the data? + (data-buffer uint8 :dynamic :offset 16) + ) + (:methods + (new (symbol type int) _type_ 0) + ) + :method-count-assert 9 + :size-assert #x18 + :flag-assert #x900000018 + ) + +(defmethod new dma-buffer ((allocation symbol) (type-to-make type) (size int)) + "Allocate a new dma-buffer with size bytes of space" + (local-vars (v0-0 dma-buffer)) + ;; we really get size + 4 bytes I think... + (set! v0-0 + (object-new allocation type-to-make + (+ (+ size -4) (the-as int (-> type-to-make size))) + ) + ) + (set! (-> v0-0 base) (-> v0-0 data)) + (set! (-> v0-0 allocated-length) size) + v0-0 + ) + +(defun dma-buffer-inplace-new ((obj dma-buffer) (size int)) + "Initialize a DMA buffer in place. Doesn't set the type of the memory" + (set! (-> obj base) (-> obj data)) + (set! (-> obj allocated-length) size) + obj + ) + +(defmethod length dma-buffer ((obj dma-buffer)) + "Get the size of the buffer" + (-> obj allocated-length) + ) + +(defmethod asize-of dma-buffer ((obj dma-buffer)) + "Get the size in memory of the object" + (+ (+ (-> obj allocated-length) -4) (the-as int (-> dma-buffer size))) + ) + +(defun dma-buffer-length ((arg0 dma-buffer)) + "Get length used in quadwords, rounded down" + (shr (+ (&- (-> arg0 base) (-> arg0 data)) 15) 4) + ) + +(defun dma-buffer-free ((arg0 dma-buffer)) + "Get the number of free quadwords, rounded down." + (the-as int + (shr (+ (&- (-> arg0 end) (-> arg0 base)) 15) 4) + ) + ) + +(defun dma-buffer-add-vu-function ((dma-buf dma-buffer) (vu-func vu-function) (arg2 int)) + "Add DMA chain instructions to load the given VU function to VU program memory. + The destination address in VU memory is specified inside of the vu-function. + if arg2 = 0, then use FLUSHE, otherwise use FLUSHA, I think the runs _before_ the program upload. + Should run with TTE." + (local-vars + (func-ptr uint) + (origin int) + (qlen int) + (qwc-now int) + (dma-buf-2 dma-buffer) + (buf-ptr pointer) + ) + ;; our strategy is to upload the program in chunks, as we can only upload 127 or 128 quadwords at a time. + ;; it is not clear why they did 127 quadword chunks, it seems like 128 would have worked too. + + ;; the actual data to upload. + (set! func-ptr (the uint (&-> vu-func data 4))) + ;; how long it is + (set! qlen (-> vu-func qlength)) + ;; where to upload to. In 64-bit units because the PS2 is annoying. + (set! origin (-> vu-func origin)) + + ;; while we still have stuff to transfer... + (while (> qlen 0) + ;; get up to 127 quadwords. maybe they thought they lost one for the dmatag + 2 vif tags? + (set! qwc-now (min 127 qlen)) + (set! dma-buf-2 dma-buf) + ;; grab a pointer to the next free memory + (set! buf-ptr (-> dma-buf-2 base)) + + ;; We will add the following tags + ;; | 32-bit MPG VIFCode | 32-bit FLUSHX VIFCode | 64-bit DMATag | + ;; DMA Tag will the REF - indicating to transfer some other data (the program), then advance to + ;; the next quadword in this buffer for the next steps. + ;; FLUSHX makes sure the VU isn't running while we upload a program. + ;; MPG tells VIF to upload the program to the VU. + + ;; put in a DMA Tag, REF + (set! (-> (the-as (pointer int64) buf-ptr)) + (logior (logior #x30000000 ;; tag id = ref + (shr (shl qwc-now 48) 48)) ;; qwc = qwc-now + (the-as int (shr (shl (the-as uint func-ptr) 33) 1)) ;; addr = func-ptr + ) + ) + ;; VIFCODE - FLUSHE or FLUSHA, wait for previous program to finish? + (set! (-> (the-as (pointer int32) buf-ptr) 2) + (shr (shl (if (zero? arg2) 16 19) 57) 33) + ) + ;; MPG - Transfers the microgram! + ;; sets num to 0, which means 256x 64 bit units, or 128 quadwords. + ;; I think this transfers one quadword too many, but it's okay. + (set! (-> (the-as (pointer int32) buf-ptr) 3) + (logior (logior #x4a000000 (shr (shl origin 48) 48)) + (shr (shl (shl qwc-now 1) 56) 40) + ) + ) + ;; advance buffer pointer to next quadword. + (set! (-> dma-buf-2 base) (&-> (the (pointer uint32) buf-ptr) 4)) + ;; advance data pointer + (set! func-ptr (+ func-ptr (the-as uint (shl qwc-now 4)))) + ;; count down transfered quads + (set! qlen (- qlen qwc-now)) + ;; source pointer advances by doublewords... + (set! origin (+ origin (shl qwc-now 1))) + ) + '#f + ) + +(defun dma-buffer-send ((chan dma-bank) (buf dma-buffer)) + "Send the DMA buffer! DOES NOT TRANSFER TAG." + (when (< (-> buf allocated-length) + (&- (-> buf base) (-> buf data)) + ) + ;; oops. we overflowed the DMA buffer. die. + (segfault) + ) + (dma-send + chan + (the-as uint (-> buf data)) + (the-as uint (dma-buffer-length buf)) + ) + ) + +(defun dma-buffer-send-chain ((chan dma-bank-source) (buf dma-buffer)) + "Send the DMA buffer! Sends the tags" + (when (< (-> buf allocated-length) + (&- (-> buf base) (-> buf data)) + ) + ;; oops. we overflowed the DMA buffer. die. + (segfault) + ) + (dma-send-chain + chan + (the-as uint (-> buf data)) + ) + ) diff --git a/goal_src/engine/dma/dma-disasm.gc b/goal_src/engine/dma/dma-disasm.gc index 46694a099d..a3d9a90978 100644 --- a/goal_src/engine/dma/dma-disasm.gc +++ b/goal_src/engine/dma/dma-disasm.gc @@ -5,3 +5,17 @@ ;; name in dgo: dma-disasm ;; dgos: GAME, ENGINE +(deftype vif-disasm-element (structure) + ((mask uint32 :offset-assert 0) + (tag uint32 :offset-assert 4) + (val uint32 :offset-assert 8) + (print uint32 :offset-assert 12) + (string1 string :offset-assert 16) + (string2 string :offset-assert 20) + ) + :method-count-assert 9 + :size-assert #x18 + :flag-assert #x900000018 + ) + + diff --git a/goal_src/engine/dma/dma-h.gc b/goal_src/engine/dma/dma-h.gc index 0fb791e8ba..2ea615d466 100644 --- a/goal_src/engine/dma/dma-h.gc +++ b/goal_src/engine/dma/dma-h.gc @@ -5,3 +5,304 @@ ;; name in dgo: dma-h ;; dgos: GAME, ENGINE +;; Constants/type for the PS2 DMA System. +;; There are a number of DMA channels. +;; The PS2 supports several types of DMA, including simple chunk transfer and more complicated +;; "chain" transfers, where the hardware can follow a linked data-structure. + +;; In OpenGOAL, "DMA" will be instant. By default, DMA syncs will be disabled by this flag. +(defglobalconstant INSTANT_DMA #t) + +;; count returned by dma-sync-with-count +;; when instant dma is enabled. +(defglobalconstant INSTANT_DMA_COUNT 123) + +;; DMA Channel Control Register. This starts the DMA and can be checked to see if it done. +(deftype dma-chcr (uint32) + ((dir uint8 :offset 0 :size 1) ;; 1 - from memory + (mod uint8 :offset 2 :size 2) ;; normal, chain, interleave + (asp uint8 :offset 4 :size 2) ;; none, 1, 2 + (tte uint8 :offset 6 :size 1) ;; transfer tag (sc only) + (tie uint8 :offset 7 :size 1) ;; tag interrupt + (str uint8 :offset 8 :size 1) ;; start! + (tag uint16 :offset 16) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +(defmethod inspect dma-chcr ((obj dma-chcr)) + (format #t "~Tdir: ~D~%" (-> obj dir)) + (format #t "~Tmod: ~D~%" (-> obj mod)) + (format #t "~Tasp: ~D~%" (-> obj asp)) + (format #t "~Ttte: ~D~%" (-> obj tte)) + (format #t "~Ttie: ~D~%" (-> obj tie)) + (format #t "~Tstr: ~D~%" (-> obj str)) + (format #t "~Ttag: #x~X~%" (-> obj tag)) + obj + ) + +;; Most basic DMA register layout +(deftype dma-bank (structure) + ((chcr dma-chcr :offset 0) ;; control register + (madr uint32 :offset 16) ;; memory address + (qwc uint32 :offset 32) ;; quadword count + ) + :method-count-assert 9 + :size-assert #x24 + :flag-assert #x900000024 + ) + +;; DMA register layout for channels supporting source-chain +(deftype dma-bank-source (dma-bank) + ((tadr uint32 :offset 48) ;; tag address + ) + :method-count-assert 9 + :size-assert #x34 + :flag-assert #x900000034 + ) + +;; The DMA source chain supports a two-entry "call stack" of tags. +;; The tag addresses are stored here. +(deftype dma-bank-vif (dma-bank-source) + ((as0 uint32 :offset 64) ;; pushed tag register + (as1 uint32 :offset 80) ;; pushed tag register + ) + :method-count-assert 9 + :size-assert #x54 + :flag-assert #x900000054 + ) + +;; The toSPR and fromSPR DMA channels require a second address in the scratchpad. +;; This is an offset from the start of SPR. +(deftype dma-bank-spr (dma-bank-source) + ((sadr uint32 :offset 128) ;; spad address. + ) + :method-count-assert 9 + :size-assert #x84 + :flag-assert #x900000084 + ) + +(defconstant VIF0_DMA_BANK (the dma-bank-vif #x10008000)) +(defconstant VIF1_DMA_BANK (the dma-bank-vif #x10009000)) +;; gif, ipuFrom, ipTop, sif0, sif1, sif2 believed unused. +(defconstant SPR_FROM_BANK (the dma-bank-spr #x1000d000)) +(defconstant SPR_TO_BANK (the dma-bank-spr #x1000d400)) + +;; D_CTRL, master DMA control register, shraed for all channels. +(deftype dma-ctrl (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; D_ENABLEW, D_ENABLER? +(deftype dma-enable (uint32) + () + :flag-assert #x900000004 + ) + +;; D_SQWC +(deftype dma-sqwc (uint32) + () + :flag-assert #x900000004 + ) + +;; Shared DMA control registers. +(deftype dma-bank-control (structure) + ((ctrl dma-ctrl :offset 0) + (stat uint32 :offset 16) + (pcr uint32 :offset 32) + (sqwc dma-sqwc :offset 48) + (rbsr uint32 :offset 64) + (rbor uint32 :offset 80) + (stadr uint32 :offset 96) + (enabler uint32 :offset 5408) + (enablew uint32 :offset 5520) + ) + :method-count-assert 9 + :size-assert #x1594 + :flag-assert #x900001594 + ) + +(defconstant DMA_CONTROL_BANK (the dma-bank-control #x1000e000)) + +;; Seems to be unused. The vu-function type is used instead. +(deftype vu-code-block (basic) + ((name basic :offset-assert 4) + (code uint32 :offset-assert 8) + (size int32 :offset-assert 12) + (dest-address uint32 :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) + +;; ?? not sure what this is. +(deftype vu-stat (uint64) + () + :flag-assert #x900000008 + ) + +;; In source chain mode, the DMA controller reads "DMAtag"s to determine addresses +;; sizes, and the next thing to transfer. +;; A tag is 8 bytes. +(deftype dma-tag (uint64) + ((qwc uint16 :offset 0) ;; quadword count + (pce uint8 :offset 26 :size 2) ;; priority (source mode) + (id uint8 :offset 28 :size 3) ;; ID (what the tag means) + (irq uint8 :offset 31 :size 1) ;; interrupt at the end? + (addr uint32 :offset 32 :size 31) ;; address (31 bits) + (spr uint8 :offset 63 :size 1) ;; spr or not flag. + ) + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; A DMA bucket is a way of organizing data within a dma buffer. +;; The buckets themselves live inside in the dma buffer. +;; the addr field of their tag should point to the next bucket. +;; This is not a PS2 hardware thing +(deftype dma-bucket (structure) + ((tag dma-tag :offset-assert 0) ;; the DMA tag to transfer the bucket's data + (last (pointer uint64) :offset-assert 8) ;; the last tag of this bucket. + (dummy uint32 :offset-assert 12) ;; empty space. + (next uint32 :offset 4) ;; this overlaps with the addr bit-field of the dma-tag + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +;; ?? +(deftype vif-mask (uint32) + () + :flag-assert #x900000004 + ) + +;; ?? +(deftype vif-stcycl-imm (uint16) + () + :flag-assert #x900000002 + ) + +;; ?? +(deftype vif-unpack-imm (uint16) + () + :flag-assert #x900000002 + ) + +;; The VIF also has tags to control it. +;; Different VIF commands (called VIFCode) have different tag layouts. +(deftype vif-tag (uint32) + ((imm uint16 :offset 0 :size 16) + (num uint8 :offset 16 :size 8) + (cmd uint8 :offset 24 :size 8) + (irq uint8 :offset 31 :size 1) ;;? + (msk uint8 :offset 15 :size 1) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +(defmethod inspect vif-tag ((obj vif-tag)) + (format #t "~Timm: #x~X~%" (-> obj imm)) + (format #t "~Tnum: ~D~%" (-> obj num)) + (format #t "~Tcmd: ~D~%" (-> obj cmd)) + (format #t "~Tirq: ~D~%" (-> obj irq)) + (format #t "~Tmsk: ~D~%" (-> obj msk)) + obj + ) + +;; NOTE: these functions are never called +;; so they are not really modified for x86-64 +;; they were inline assembly originally + +(defun dma-sync-fast ((bank dma-bank)) + "Wait for chcr str to go to 0, indicating DMA + is complete." + (declare (inline)) + (#cond + (INSTANT_DMA + ;; nothing to do. + 0 + ) + (#t + (while (nonzero? (-> bank chcr str)) + ;; they had a precise number of nops here. + ;; it turns out that spamming the DMA registers is not a good idea + ;; because it uses the main bus that the DMA is possibly also trying to use. + (nop!) + ) + ) + ) + (none) + ) + +(defun dma-send-no-scratch ((bank dma-bank) + (madr uint32) + (qwc uint32)) + "Begin a DMA transfer, directly to the bank. + Makes sure any ongoing transfer on the channel is done + Flushes the cache. Sets dir to 0, so I don't expect + this to be used for VIF1 transfers. + Madr should not be a scratchpad address." + ((inline dma-sync-fast) bank) + (flush-cache 0) + ;; (.sync.l) + (set! (-> bank madr) madr) + (set! (-> bank qwc) qwc) + ;; (.sync.l) + + ;; this seems wrong, the set everything to 0, + ;; including dir, which is the to-memory direction + (set! (-> bank chcr) + (new 'static 'dma-chcr :str 1) + ) + (none) + ) + +(defun dma-sync-with-count ((bank dma-bank) + (count (pointer int32))) + "Wait for DMA to finish, incrementing count. + This doesn't seem like a very accurate way + to find out how long it takes..." + (#cond + (INSTANT_DMA + (set! (-> count) INSTANT_DMA_COUNT) + 0 + ) + (#t + (when (nonzero? (-> bank chcr str)) + (let ((x (-> count))) + (while (nonzero? (-> bank chcr str)) + (+! x 1) + (set! (-> count) x) + ) + ) + ) + 0 + ) + ) + ) + +(defun dma-count-until-done ((bank dma-bank) + (count (pointer int32))) + "Like the previous one, kinda" + (#cond + (INSTANT_DMA + (set! (-> count) INSTANT_DMA_COUNT) + 0 + ) + (#t + (while (nonzero? (-> bank chcr str)) + (set! (-> count) (+ 1 (-> count))) + ) + ) + ) + ) diff --git a/goal_src/engine/dma/dma.gc b/goal_src/engine/dma/dma.gc index a5ee679e4d..27a0e8611b 100644 --- a/goal_src/engine/dma/dma.gc +++ b/goal_src/engine/dma/dma.gc @@ -5,3 +5,418 @@ ;; name in dgo: dma ;; dgos: GAME, ENGINE +;; DMA send and sync functions: +;; These functions transfer existing DMA chains and buffers. +;; In general, there are two types: +;; - plain transfer of a buffer (like, src, dst, size) +;; - chain, a data structure the PS2 DMA hardware can traverse, just give it a starting address. + +;; The plan for OpenGOAL is to patch things higher up, likely in renderers or buffers. +;; So we would replace a (dma-send-chain ...) in a render with +;; (generic-dma-pc-port ...) that will pass the data along to the PC renderer. +;; these functions are just here for completeness and won't work properly on PC. +;; DMA sync functions will succeed and return instantly, so it's safe to leave those in. + +(defconstant SPR_FROM_BANK (the dma-bank-spr #x100D000)) +(defconstant SPR_TO_BANK (the dma-bank-spr #x1000D400)) + +(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." + (#cond + (INSTANT_DMA + 0) + (#t + (while (nonzero? (-> bank chcr str)) + (nop!) + ) + ) + ) + (none) + ) + +(defun dma-sync-crash ((arg0 dma-bank)) + "Try to sync DMA for a bit, then crash if we can't" + (local-vars (count int)) + (#when INSTANT_DMA + (return 0) + ) + (set! count 5000000) + ;; checking str + (while (nonzero? (logand (the-as int (-> arg0 chcr)) 256)) + (if (zero? count) + (segfault) + (set! count (+ count -1)) + ) + ) + (none) + ) + +(defun dma-send ((arg0 dma-bank) (madr uint) (qwc uint)) + "Send DMA! madr can be a scratchpad address. + Like dma-send-no-scratch, this sets chcr to zero, which may be undesirable." + (dma-sync (the-as pointer arg0) 0 0) + (flush-cache 0) + ;;(.sync.l) + (set! (-> arg0 madr) + (logior (logand #xfffffff (the-as int madr)) ;; lower 28 bits are untouched + ;; if we are transferring to the scratchpad (at 70000000) + ;; we should set bit 31 in madr, per the manual. + (if (= (logand #x70000000 (the-as int madr)) #x70000000) + (shl 32768 16) ;; set bit 31 + 0) + ) + ) + (set! (-> arg0 qwc) qwc) + ;(.sync.l) + ;; set str! + (set! (-> arg0 chcr) (new 'static 'dma-chcr :str 1)) + ;(.sync.l) + (none) + ) + +(defun dma-send-chain ((arg0 dma-bank-source) (tadr uint)) + "Send DMA! tadr should be a tag address, possibly in spad ram." + (dma-sync (the-as pointer arg0) 0 0) + (flush-cache 0) + ;(.sync.l) + (set! (-> arg0 qwc) 0) + ;; adjust address + (set! (-> arg0 tadr) + (logior (logand 268435455 (the-as int tadr)) + (if (= (logand 1879048192 (the-as int tadr)) 1879048192) + (shl 32768 16) + 0) + ) + ) + ;(.sync.l) + ;;(set! (-> arg0 chcr) 325) + (set! (-> arg0 chcr) + (new 'static 'dma-chcr + :dir 1 ;; from memory + :mod 1 ;; source chain + :tte 1 ;; send tags + :str 1) ;; go! + ) + ;(.sync.l) + (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." + (dma-sync (the-as pointer arg0) 0 0) + (flush-cache 0) + ;;(.sync.l) + (set! (-> arg0 qwc) 0) + (set! + (-> arg0 tadr) + (logior + (logand 268435455 (the-as int arg1)) + (the-as + uint + (if (= (logand 1879048192 (the-as int arg1)) 1879048192) (shl 32768 16) 0) + ) + ) + ) + ;;(.sync.l) + (set! (-> arg0 chcr) + (new 'static 'dma-chcr + :dir 1 ;; from memory + :mod 1 ;; source chain + :tte 0 ;; no tags + :str 1) ;; go! + ) + ;;(.sync.l) + (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." + (local-vars (v0-1 int)) + (dma-sync (the-as pointer arg0) 0 0) + (.sync.l) + (set! (-> arg0 qwc) 0) + (set! + (-> arg0 tadr) + (logior + (logand 268435455 (the-as int arg1)) + (the-as + uint + (if (= (logand 1879048192 (the-as int arg1)) 1879048192) (shl 32768 16) 0) + ) + ) + ) + ;;(.sync.l) + ;;(set! (-> arg0 chcr) 325) + (set! (-> arg0 chcr) + (new 'static 'dma-chcr + :dir 1 + :mod 1 + :tte 1 + :str 1) + ) + ;;(.sync.l) + (set! v0-1 0) + (none) + ) + +(defun dma-send-to-spr ((sadr uint) (madr uint) (qwc uint) (sync symbol)) + "Transfer data to spr" + (local-vars (s5-0 dma-bank-spr)) + (set! s5-0 SPR_TO_BANK) + (dma-sync (the-as pointer s5-0) 0 0) + (flush-cache 0) + (.sync.l) + (set! (-> s5-0 madr) (logand #xFFFFFFF (the-as int madr))) + (set! (-> s5-0 sadr) (logand #xFFFFFFF (the-as int sadr))) + (set! (-> s5-0 qwc) qwc) + ;;(.sync.l) + (set! (-> s5-0 chcr) (new 'static 'dma-chcr :str 1)) + ;;(.sync.l) + (if sync + (dma-sync (the-as pointer s5-0) 0 0)) + (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." + (local-vars (s5-0 dma-bank-spr)) + (set! s5-0 SPR_TO_BANK) + (dma-sync (the-as pointer s5-0) 0 0) + ;;(.sync.l) + (set! (-> s5-0 madr) (logand 268435455 (the-as int madr))) + (set! (-> s5-0 sadr) (logand 268435455 (the-as int sadr))) + (set! (-> s5-0 qwc) qwc) + ;;(.sync.l) + (set! (-> s5-0 chcr) (new 'static 'dma-chcr :str 1)) + ;;(.sync.l) + (if sync (dma-sync (the-as pointer s5-0) 0 0)) + (none) + ) + +(defun dma-send-from-spr ((madr uint) (sadr uint) (qwc uint) (sync symbol)) + "Transfer from spr." + (local-vars (s5-0 dma-bank-spr)) + (set! s5-0 SPR_FROM_BANK) + (dma-sync (the-as pointer s5-0) 0 0) + (flush-cache 0) + ;;(.sync.l) + (set! (-> s5-0 madr) (logand 268435455 (the-as int madr))) + (set! (-> s5-0 sadr) (logand 268435455 (the-as int sadr))) + (set! (-> s5-0 qwc) qwc) + ;;(.sync.l) + (set! (-> s5-0 chcr) (new 'static 'dma-chcr :str 1)) + ;;(.sync.l) + (if sync (dma-sync (the-as pointer s5-0) 0 0)) + (none) + ) + +(defun dma-send-from-spr-no-flush ((madr uint) (sadr uint) (qwc uint) (sync symbol)) + "Transfer from spr, don't flush the cache." + (local-vars (s5-0 dma-bank-spr)) + (set! s5-0 SPR_FROM_BANK) + (dma-sync (the-as pointer s5-0) 0 0) + ;;(.sync.l) + (set! (-> s5-0 madr) (logand 268435455 (the-as int madr))) + (set! (-> s5-0 sadr) (logand 268435455 (the-as int sadr))) + (set! (-> s5-0 qwc) qwc) + ;;(.sync.l) + (set! (-> s5-0 chcr) (new 'static 'dma-chcr :str 1)) + ;;(.sync.l) + (if sync (dma-sync (the-as pointer s5-0) 0 0)) + (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 + (format 0 "[dma.gc] skipping dma-initialize for PC port~%") + (return 0) + ) + + (set! (-> VIF0_BANK err) + (logior (logand (-> VIF0_BANK err) (the-as uint -3)) 2) + ) + (set! (-> (the vif-bank #x10003c00) err) + (logior (logand (-> VIF1_BANK err) (the-as uint -3)) 2) + ) + (none) + ) + +(defun clear-vu0-mem () + "Clear the data memory of VU0, filling it with abadbeef + This uses the slow memory mapping of VU0's data memory at 0x11004000" + (local-vars + (v1-0 (pointer uint32)) + (a0-0 int) + ) + (set! v1-0 (the (pointer uint32) #x11004000)) + (set! a0-0 0) + (while (< a0-0 1024) + (set! (-> v1-0 a0-0) #xabadbeef) + (set! a0-0 (+ a0-0 1)) + ) + (none) + ) + +(defun clear-vu1-mem () + "Clear the data memory of VU1, filling it with abadbeef + This uses the slow memory mapping of VU0's data memory at 0x11004000" + (local-vars + (v1-0 (pointer uint32)) + (a0-0 int) + ) + (set! v1-0 (the (pointer uint32) #x1100c000)) + (set! a0-0 0) + (while (< a0-0 4096) + (set! (-> v1-0 a0-0) #xabadbeef) + (set! a0-0 (+ a0-0 1)) + ) + (none) + ) + +(defun dump-vu1-mem () + "Print VU1 memory to runtime stdout." + (local-vars (s5-0 int) (gp-0 (pointer uint32))) + (set! gp-0 (the (pointer uint32) #x1100c000)) + (set! s5-0 0) + (while (< s5-0 1024) ;; 1k quadwords + (format 0 "~4,'0X: ~8,'0X ~8,'0X ~8,'0X ~8,'0X" + s5-0 + (-> gp-0 (shl s5-0 2)) + (-> gp-0 (+ (shl s5-0 2) 1)) + (-> gp-0 (+ (shl s5-0 2) 2)) + (-> gp-0 (+ (shl s5-0 2) 3)) + ) + (format 0 " ~F ~F ~F ~F ~%" + (-> gp-0 (shl s5-0 2)) + (-> gp-0 (+ (shl s5-0 2) 1)) + (-> gp-0 (+ (shl s5-0 2) 2)) + (-> gp-0 (+ (shl s5-0 2) 3)) + ) + (set! s5-0 (+ s5-0 1)) + ) + (none) + ) + +(defun dump-vu1-range ((start uint) (total-count uint)) + "Print part of VU1 memory to runtime stdout." + (local-vars (s3-0 int) (s2-0 int) (s4-0 (pointer uint32))) + (set! s4-0 (the (pointer uint32) #x1100c000)) + (set! s3-0 0) + (while (< s3-0 (the-as int total-count)) + (set! s2-0 (+ s3-0 (the-as int start))) + (format 0 "~4,'0X: ~8x ~8x ~8x ~8x" + s2-0 + (-> s4-0 (shl s2-0 2)) + (-> s4-0 (+ (shl s2-0 2) 1)) + (-> s4-0 (+ (shl s2-0 2) 2)) + (-> s4-0 (+ (shl s2-0 2) 3)) + ) + (format 0 " ~F ~F ~F ~F ~%" + (-> s4-0 (shl s2-0 2)) + (-> s4-0 (+ (shl s2-0 2) 1)) + (-> s4-0 (+ (shl s2-0 2) 2)) + (-> s4-0 (+ (shl s2-0 2) 3)) + ) + (set! s3-0 (+ s3-0 1)) + ) + '#f + ) + +;; if we send junk DMA data due to an engine bug, the PS2 will eventually time out the transfer. +;; in this case, the main loop will attempt to reset everything to hopefully recover. +;; this value is the PAL/NTSC constant for the Sony reset functions. +;; if we switch PAL/NTSC during runtime, we should update this. +(define *video-reset-parm* 2) + +(defun reset-vif1-path () + "When things go wrong, totally reset vif1." + ;; inspect the banks + (#unless PC_PORT + ((method-of-type dma-bank-vif inspect) VIF1_DMA_BANK) + ((method-of-type vif-bank inspect) VIF1_BANK) + ) + ;; sceGsResetPath + (reset-path) + ;; sceGsResetGraph + (reset-graph 1 1 *video-reset-parm* 1) + (format 0 "gkernel: vif1 path reset!~%") + (none) + ) + +(defun ultimate-memcpy ((dst pointer) (src pointer) (size-bytes uint)) + "Fast memcpy using the scratchpad. Will blow away everything in scratch. + Rounds to nearest quadword for size, dst and source should be aligned 16-bytes." + (local-vars + (qwc-transferred-now uint) + (qwc-remaining uint) + (spr-from-bank dma-bank-spr) + (spr-to-bank dma-bank-spr) + ) + (set! spr-to-bank (the dma-bank-spr #x1000d400)) + (set! spr-from-bank (the dma-bank-spr #x1000d000)) + (set! qwc-remaining (shr size-bytes 4)) + (flush-cache 0) + (dma-sync (the-as pointer spr-to-bank) 0 0) + (dma-sync (the-as pointer spr-from-bank) 0 0) + (while (> qwc-remaining 0) + ;; figure out how much to transfer, limited by 1024 quadword size of spad. + (set! qwc-transferred-now qwc-remaining) + (when (< (the-as uint 1024) qwc-transferred-now) + (set! qwc-transferred-now (the uint 1024)) + ) + (set! qwc-remaining (- qwc-remaining (the-as uint qwc-transferred-now))) + + ;;(.sync.l) + ;; set up dma + (set! (-> spr-to-bank madr) (the uint src)) + (set! (-> spr-to-bank sadr) 0) + (set! (-> spr-to-bank qwc) qwc-transferred-now) + ;;(.sync.l) + ;; start dma + (set! (-> spr-to-bank chcr) (new 'static 'dma-chcr :str 1)) + ;;(.sync.l) + ;; sync + (dma-sync (the-as pointer spr-to-bank) 0 0) + + ;; advance source pointer. + (set! src (&+ src (the-as uint (shl qwc-transferred-now 4)))) + + ;; setup transfer back + (set! (-> spr-from-bank madr) (the uint dst)) + (set! (-> spr-from-bank sadr) 0) + (set! (-> spr-from-bank qwc) qwc-transferred-now) + ;; transfer! + ;;(.sync.l) + (set! (-> spr-from-bank chcr) (new 'static 'dma-chcr :str 1)) + ;;(.sync.l) + ;; sync! + (dma-sync (the-as pointer spr-from-bank) 0 0) + ;; advance dst. + (set! dst (&+ dst (the-as uint (shl qwc-transferred-now 4)))) + ) + (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." + (segfault) + (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" + (segfault) + (none) + ) + +;; configuration required to work around hardware bug. +;; doesn't do anything important +(dma-initialize) diff --git a/goal_src/engine/gfx/hw/video-h.gc b/goal_src/engine/gfx/hw/video-h.gc index 3aeddf2b1e..55ec373cfc 100644 --- a/goal_src/engine/gfx/hw/video-h.gc +++ b/goal_src/engine/gfx/hw/video-h.gc @@ -5,3 +5,45 @@ ;; name in dgo: video-h ;; dgos: GAME, ENGINE +(deftype video-parms (structure) + ((set-video-mode basic :offset-assert 0) + (reset-video-mode basic :offset-assert 4) + (screen-sy int32 :offset-assert 8) + (screen-hy int32 :offset-assert 12) + (screen-miny int32 :offset-assert 16) + (screen-maxy int32 :offset-assert 20) + (screen-masky int32 :offset-assert 24) + (display-dx int32 :offset-assert 28) + (display-dy int32 :offset-assert 32) + (screen-pages-high int32 :offset-assert 36) + (_pad int64) + (relative-x-scale float :offset-assert 48) + (relative-y-scale float :offset-assert 52) + (_pad2 int64) + (relative-x-scale-reciprical float :offset-assert 64) + (relative-y-scale-reciprical float :offset-assert 68) + ) + :method-count-assert 9 + :size-assert #x48 + :flag-assert #x900000048 + ) + +(define *video-parms* + (new 'static 'video-parms + :set-video-mode #f + :reset-video-mode #f + :screen-sy 224 + :screen-hy 112 + :screen-miny 1824 + :screen-maxy 2272 + :screen-masky #xdf + :display-dx 0 + :display-dy 8 + :screen-pages-high 7 + :relative-x-scale 1.0 + :relative-y-scale 1.0 + :relative-x-scale-reciprical 1.0 + :relative-y-scale-reciprical 0.0 ;; ?? + ) + ) + diff --git a/goal_src/engine/gfx/hw/vu1-user-h.gc b/goal_src/engine/gfx/hw/vu1-user-h.gc index 705d6a090c..c5fac46779 100644 --- a/goal_src/engine/gfx/hw/vu1-user-h.gc +++ b/goal_src/engine/gfx/hw/vu1-user-h.gc @@ -5,3 +5,56 @@ ;; name in dgo: vu1-user-h ;; dgos: GAME, ENGINE +;; VU1 renderers are enabled/disabled with a bitmask. + +;; I believe this is renderers which can be enabled/disabled in the debug menu? +(define *vu1-enable-user-menu* + #x1FFFF8) + +;; by default, all off. +;; the menu renderers get copied to this on each frame +(define *vu1-enable-user* 0) + +;; a dma "sink" is somewhere where a renderer can put stuff. +(deftype dma-foreground-sink (basic) + ((bucket int32 :offset-assert 4) ;; not sure if this is a bucket index or pointer? + (foreground-texture-page int8 :offset-assert 8) ;; ? + (foreground-texture-level int8 :offset-assert 9) ;; ? + (foreground-output-bucket int8 :offset-assert 10) ;; ? + ) + :method-count-assert 9 + :size-assert #xb + :flag-assert #x90000000b + ) + +;; additional info for the generic renderer +(deftype generic-bucket-state (structure) + ((gifbuf-adr uint32 :offset-assert 0) + (inbuf-adr uint32 :offset-assert 4) + ) + :pack-me + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +;; sink for the generic renderer, a normal sink + extra data. +(deftype generic-dma-foreground-sink (dma-foreground-sink) + ((state generic-bucket-state :inline :offset-assert 12) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) + +;; group of sinks used for the foreground renderers. +(deftype dma-foreground-sink-group (basic) + ((sink dma-foreground-sink 3 :offset-assert 4) + (merc-sink dma-foreground-sink :offset 4) + (generic-sink generic-dma-foreground-sink :offset 8) + (level basic :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) diff --git a/goal_src/engine/ps2/timer-h.gc b/goal_src/engine/ps2/timer-h.gc index fbb92bce54..7879cc9160 100644 --- a/goal_src/engine/ps2/timer-h.gc +++ b/goal_src/engine/ps2/timer-h.gc @@ -76,7 +76,9 @@ ) ;; segfaults OpenGOAL as it does not support ps2 EE timers -; (timer-init (the-as timer-bank EE_TIMER1) (the-as timer-mode #x82)) +(#unless PC_PORT + (timer-init (the-as timer-bank EE_TIMER1) (the-as timer-mode #x82)) + ) (deftype profile-frame (structure) diff --git a/goal_src/engine/ps2/vif-h.gc b/goal_src/engine/ps2/vif-h.gc index 15908f81d3..6ffc04395c 100644 --- a/goal_src/engine/ps2/vif-h.gc +++ b/goal_src/engine/ps2/vif-h.gc @@ -5,3 +5,96 @@ ;; name in dgo: vif-h ;; dgos: GAME, ENGINE +;; Types related to VIF: the PS2's Vector Interface. +;; Each of VU0 and VU1 has a VIF which is used to sent/receive data. +;; The VIFs are controller by registers and fed data using DMA + +;;VIF0_STAT or VIF1_STAT bitfields +(deftype vif-stat (uint32) + ((vps uint8 :offset 0 :size 2) + (vew uint8 :offset 2 :size 1) + (mrk uint8 :offset 6 :size 1) + (vss uint8 :offset 8 :size 1) + (vfs uint8 :offset 9 :size 1) + (vis uint8 :offset 10 :size 1) + (int uint8 :offset 11 :size 1) + (er0 uint8 :offset 12 :size 1) + (er1 uint8 :offset 13 :size 1) + (fqc uint8 :offset 24 :size 4) + ) + + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +(defmethod inspect vif-stat ((obj vif-stat)) + (format #t "~Tvps: ~D" (-> obj vps)) + (format #t "~Tvew: ~D" (-> obj vew)) + (format #t "~Tmrk: ~D" (-> obj mrk)) + (format #t "~Tvss: ~D" (-> obj vss)) + (format #t "~Tvfs: ~D" (-> obj vfs)) + (format #t "~Tvis: ~D" (-> obj vis)) + (format #t "~Tint: ~D" (-> obj int)) + (format #t "~Ter0: ~D" (-> obj er0)) + (format #t "~Ter1: ~D" (-> obj er1)) + (format #t "~Tfqc: ~D" (-> obj fqc)) + obj) + +;; VIF "reset" register. +(deftype vif-fbrst (uint32) + ((rst uint8 :offset 0 :size 1) + (fbk uint8 :offset 1 :size 1) + (stp uint8 :offset 2 :size 1) + (stc uint8 :offset 3 :size 1) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; Error mask register +(deftype vif-err (uint32) + ((mii uint8 :offset 0 :size 1) + (me0 uint8 :offset 1 :size 1) ;; PS2 hardware bug, must set this to 1 for correct operation. + (me1 uint8 :offset 2 :size 1) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; Common layout of hardware registers shared between the two VIFs +(deftype vif-bank (structure) + ((stat uint32 :offset-assert 0) + (fbrst uint32 :offset 16) + (err uint32 :offset 32) + (mark uint32 :offset 48) + (cycle uint32 :offset 64) + (mode uint32 :offset 80) + (num uint32 :offset 96) + (mask uint32 :offset 112) + (code uint32 :offset 128) + (itops uint32 :offset 144) + (base uint32 :offset 160) + (offset uint32 :offset 176) + (tops uint32 :offset 192) + (itop uint32 :offset 208) + (top uint32 :offset 224) + (r0 uint32 :offset 256) + (r1 uint32 :offset 272) + (r2 uint32 :offset 288) + (r3 uint32 :offset 304) + (c0 uint32 :offset 320) + (c1 uint32 :offset 336) + (c2 uint32 :offset 352) + (c3 uint32 :offset 368) + ) + :method-count-assert 9 + :size-assert #x174 + :flag-assert #x900000174 + ) + +;; PS2 VIF map. There are no VIFs in OpenGOAL. +(defconstant VIF0_BANK (the vif-bank #x10003800)) +(defconstant VIF1_BANK (the vif-bank #x10003c00)) diff --git a/goal_src/engine/sound/gsound-h.gc b/goal_src/engine/sound/gsound-h.gc index 247e8d4cb4..7f0c284885 100644 --- a/goal_src/engine/sound/gsound-h.gc +++ b/goal_src/engine/sound/gsound-h.gc @@ -5,3 +5,352 @@ ;; name in dgo: gsound-h ;; dgos: GAME, ENGINE +;; Type definitions for sound. +;; The actual sound code is all on the IOP, and the EE can send RPCs to control. +;; There is also some sort of per-frame status update, that is not included here. + +(deftype sound-id (uint32) + () + (:methods + (dummy-9 () none 9) + ) + :flag-assert #xa00000004 + ) + +(deftype sound-bank-id (uint32) + () + :flag-assert #x900000004 + ) + +;; Sound names were sometimes packed into a uint128 +(deftype sound-name (uint128) + () + :flag-assert #x900000010 + ) + +;; like should match the sound type in OVERLORD +;; This is shared between all sound RPCs. +(deftype sound-rpc-cmd (structure) + ((rsvd1 uint16 :offset-assert 0) + (command uint16 :offset-assert 2) + ) + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +(deftype sound-play-parms (structure) + ((mask uint16 :offset-assert 0) + (pitch-mod int16 :offset-assert 2) + (bend int16 :offset-assert 4) + (fo-min int16 :offset-assert 6) + (fo-max int16 :offset-assert 8) + (fo-curve int8 :offset-assert 10) + (priority int8 :offset-assert 11) + (volume int32 :offset-assert 12) + (trans float 3 :offset-assert 16) ;; guess on type here + (group uint8 :offset-assert 28) + ) + :pack-me + :method-count-assert 9 + :size-assert #x1d + :flag-assert #x90000001d + ) + +(deftype sound-rpc-bank-cmd (sound-rpc-cmd) + ((bank-name uint128 :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +(deftype sound-rpc-sound-cmd (sound-rpc-cmd) + ((id uint32 :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +(deftype sound-rpc-group-cmd (sound-rpc-cmd) + ((group uint8 :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +(deftype sound-rpc-load-bank (sound-rpc-bank-cmd) + () + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +(deftype sound-rpc-load-music (sound-rpc-bank-cmd) + () + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +(deftype sound-rpc-unload-bank (sound-rpc-bank-cmd) + () + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +(deftype sound-rpc-play (sound-rpc-sound-cmd) + ((name uint128 :offset-assert 16) + (parms sound-play-parms :inline :offset-assert 32) + ) + :method-count-assert 9 + :size-assert #x3d + :flag-assert #x90000003d + ) + +(deftype sound-rpc-pause-sound (sound-rpc-sound-cmd) + () + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +(deftype sound-rpc-stop-sound (sound-rpc-sound-cmd) + () + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +(deftype sound-rpc-continue-sound (sound-rpc-sound-cmd) + () + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +(deftype sound-rpc-set-param (sound-rpc-sound-cmd) + ((parms sound-play-parms :inline :offset-assert 8) + (auto-time int32 :offset-assert 40) + (auto-from int32 :offset-assert 44) + ) + :method-count-assert 9 + :size-assert #x30 + :flag-assert #x900000030 + ) + +(deftype sound-rpc-set-master-volume (sound-rpc-group-cmd) + ((volume int32 :offset-assert 8) + ) + :method-count-assert 9 + :size-assert #xc + :flag-assert #x90000000c + ) + +(deftype sound-rpc-pause-group (sound-rpc-group-cmd) + () + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +(deftype sound-rpc-stop-group (sound-rpc-group-cmd) + () + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +(deftype sound-rpc-continue-group (sound-rpc-group-cmd) + () + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +(deftype sound-rpc-get-irx-version (sound-rpc-cmd) + ((major uint32 :offset-assert 4) + (minor uint32 :offset-assert 8) + (ee-addr uint32 :offset-assert 12) + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +(deftype sound-rpc-set-language (sound-rpc-cmd) + ((lang uint32 :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ) + +(deftype sound-rpc-set-falloff-curve (sound-rpc-cmd) + ((curve int32 :offset-assert 4) + (falloff int32 :offset-assert 8) + (ease int32 :offset-assert 12) + ) + :method-count-assert 9 + :size-assert #x10 + :flag-assert #x900000010 + ) + +(deftype sound-rpc-set-sound-falloff (sound-rpc-cmd) + ((name uint128 :offset-assert 16) + (curve int32 :offset-assert 32) + (min int32 :offset-assert 36) + (max int32 :offset-assert 40) + ) + :method-count-assert 9 + :size-assert #x2c + :flag-assert #x90000002c + ) + +(deftype sound-rpc-reload-info (sound-rpc-cmd) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +(deftype sound-rpc-set-reverb (sound-rpc-cmd) + ((core uint8 :offset-assert 4) + (reverb int32 :offset-assert 8) + (left uint32 :offset-assert 12) + (right uint32 :offset-assert 16) + ) + :method-count-assert 9 + :size-assert #x14 + :flag-assert #x900000014 + ) + +(deftype sound-rpc-set-ear-trans (sound-rpc-cmd) + ((ear-trans float 3 :offset-assert 4) ;; guess on float, may be fixed point + (cam-trans float 3 :offset-assert 16) + (cam-angle int32 :offset-assert 28) + ) + :method-count-assert 9 + :size-assert #x20 + :flag-assert #x900000020 + ) + +(deftype sound-rpc-set-flava (sound-rpc-cmd) + ((flava uint8 :offset-assert 4) + ) + :method-count-assert 9 + :size-assert #x5 + :flag-assert #x900000005 + ) + +(deftype sound-rpc-shutdown (sound-rpc-cmd) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +(deftype sound-rpc-list-sounds (sound-rpc-cmd) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +(deftype sound-rpc-unload-music (sound-rpc-cmd) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ) + +;; union of all the possible sound commands. +(deftype sound-rpc-union (structure) + ((data uint32 20 :offset-assert 0) + (load-bank sound-rpc-load-bank :offset 0) + (unload-bank sound-rpc-unload-bank :offset 0) + (play sound-rpc-play :offset 0) + (pause-sound sound-rpc-pause-sound :offset 0) + (stop-sound sound-rpc-stop-sound :offset 0) + (continue-sound sound-rpc-continue-sound :offset 0) + (set-param sound-rpc-set-param :offset 0) + (set-master-volume sound-rpc-set-master-volume :offset 0) + (pause-group sound-rpc-pause-group :offset 0) + (stop-group sound-rpc-stop-group :offset 0) + (continue-group sound-rpc-continue-group :offset 0) + (get-irx-version sound-rpc-get-irx-version :offset 0) + (set-falloff-curve sound-rpc-set-falloff-curve :offset 0) + (set-sound-falloff sound-rpc-set-sound-falloff :offset 0) + (reload-info sound-rpc-reload-info :offset 0) + (set-language sound-rpc-set-language :offset 0) + (set-reverb sound-rpc-set-reverb :offset 0) + (set-ear-trans sound-rpc-set-ear-trans :offset 0) + (set-flava sound-rpc-set-flava :offset 0) + (shutdown sound-rpc-shutdown :offset 0) + (list-sounds sound-rpc-list-sounds :offset 0) + (unload-music sound-rpc-unload-music :offset 0) + ) + :method-count-assert 9 + :size-assert #x50 + :flag-assert #x900000050 + ) + +(deftype sound-spec (basic) + ((mask uint16 :offset-assert 4) + (num float :offset-assert 8) + (group uint8 :offset-assert 12) + (sound-name-char uint8 16 :offset 16) + (sound-name uint128 :offset 16) + (trans float 4 :offset-assert 32) ;; guess + (volume int32 :offset-assert 48) + (pitch-mod int32 :offset-assert 52) + (bend int32 :offset-assert 56) + (fo-min int16 :offset-assert 60) + (fo-max int16 :offset-assert 62) + (fo-curve int8 :offset-assert 64) + (priority int8 :offset-assert 65) + (auto-time int32 :offset-assert 68) + (auto-from int32 :offset-assert 72) + ) + :method-count-assert 9 + :size-assert #x4c + :flag-assert #x90000004c + ) + +(define *current-sound-id* (the sound-id 65536)) + +(deftype ambient-sound (basic) + ((spec basic :offset-assert 4) + (playing-id uint32 :offset-assert 8) + (trans vector :inline :offset-assert 16) + (name uint128 :offset-assert 32) + (play-time uint64 :offset-assert 48) + (time-base uint64 :offset-assert 56) + (time-random uint64 :offset-assert 64) + (volume int32 :offset-assert 72) + (pitch int32 :offset-assert 76) + (falloff-near int32 :offset-assert 80) + (falloff-far int32 :offset-assert 84) + (falloff-mode int32 :offset-assert 88) + (params uint32 :offset-assert 92) + (param-count int32 :offset-assert 96) + (entity basic :offset-assert 100) + (sound-count int32 :offset-assert 104) + ) + :method-count-assert 14 + :size-assert #x6c + :flag-assert #xe0000006c + (:methods + (dummy-9 () none 9) + (dummy-10 () none 10) + (dummy-11 () none 11) + (dummy-12 () none 12) + (dummy-13 () none 13) + ) + ) + +(define *sound-bank-1* #f) +(define *sound-bank-2* #f) diff --git a/goal_src/kernel-defs.gc b/goal_src/kernel-defs.gc index dff74da1a1..3f313e3602 100644 --- a/goal_src/kernel-defs.gc +++ b/goal_src/kernel-defs.gc @@ -114,13 +114,14 @@ ;; put-display-env ;; syncv ;; sync-path -;; reset-path -;; rest-graph +(define-extern reset-path (function none)) +(define-extern reset-graph (function int int int int none)) ;; dma-sync +(define-extern dma-sync (function pointer int int int)) ;; gs-put-imr ;; gs-get-imr ;; gs-store-image -;; flush-cache +(define-extern flush-cache (function int none)) ;; cpad-open ;; cpad-get-data ;; install-handler diff --git a/goal_src/kernel/gcommon.gc b/goal_src/kernel/gcommon.gc index 0e0a2a7b08..ac19e45ed4 100644 --- a/goal_src/kernel/gcommon.gc +++ b/goal_src/kernel/gcommon.gc @@ -20,6 +20,8 @@ (defconstant RELOC_METHOD_ID 7) ;; or login? (defconstant MEM_USAGE_METHOD_ID 8) +(defglobalconstant PC_PORT #t) + ;; distance from a symbol pointer to a (pointer string) ;; this relies on the memory layout of the symbol table ;; this must match SYM_INFO_OFFSET in goal_constants.h + offset of the str field in struct SymUpper. diff --git a/goalc/compiler/compilation/Macro.cpp b/goalc/compiler/compilation/Macro.cpp index 2fd326d730..cc55da1ab1 100644 --- a/goalc/compiler/compilation/Macro.cpp +++ b/goalc/compiler/compilation/Macro.cpp @@ -9,13 +9,9 @@ using namespace goos; bool Compiler::try_getting_macro_from_goos(const goos::Object& macro_name, goos::Object* dest) { Object macro_obj; bool got_macro = false; - try { - macro_obj = m_goos.eval_symbol(macro_name, m_goos.goal_env.as_env()); - if (macro_obj.is_macro()) { - got_macro = true; - } - } catch (std::runtime_error& e) { - got_macro = false; + if (m_goos.eval_symbol(macro_name, m_goos.goal_env.as_env(), ¯o_obj) && + macro_obj.is_macro()) { + got_macro = true; } if (got_macro) { diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 068129265a..91df769cdd 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -779,7 +779,8 @@ Val* Compiler::compile_static_new(const goos::Object& form, } throw_compiler_error(form, - "Cannot do a static new of a {} because it is not a bitfield or structure."); + "Cannot do a static new of a {} because it is not a bitfield or structure.", + type.print()); return get_none(); } diff --git a/scripts/decomp_progress.py b/scripts/decomp_progress.py new file mode 100644 index 0000000000..f085180d94 --- /dev/null +++ b/scripts/decomp_progress.py @@ -0,0 +1,59 @@ +import os +import glob +import argparse + +### Script to track decompilation progress. +### Example usage: python3 scripts/decomp_progress.py ~/jak-project/goal_src + +def get_goal_files(root_dir): + """Get all GOAL source files under root_dir""" + return [goal_file for file in os.walk(root_dir) for goal_file in glob.glob(os.path.join(file[0], '*.gc'))] + +def lines_in_file(file_path): + with open(file_path) as f: + lines = 0 + for _ in f: + lines += 1 + return lines + + +def print_table(stats): + total_lines = 0 + print("| {: <24} | {: <6} |".format("file name", "lines")) + print("-------------------------------------") + for x in stats: + print(" {: <24} | {: >6} |".format(x[0], x[1])) + total_lines += x[1] + print("-------------------------------------") + print("| {: <24} | {: >6} |".format("TOTAL", total_lines)) + print("-------------------------------------") + estimated_lines = 500000 + print("Progress: {}/{} lines ({:.2f}%)".format(total_lines, estimated_lines, 100. * total_lines / estimated_lines)) + + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument(dest='goal_src', help='the goal_src folder') + args = parser.parse_args() + all_files = get_goal_files(args.goal_src) + + file_stats = [] + + excluded_files = {"all_files.gc", "goal-lib.gc"} + + for fn in all_files: + short_name = os.path.basename(fn) + line_count = lines_in_file(fn) + if line_count == 7 or short_name in excluded_files: + # the template has 7 lines, just skip it. + continue + + file_stats.append((short_name, line_count)) + file_stats.sort(key=lambda x: x[1]) + + print_table(file_stats) + + +if __name__ == "__main__": + main() diff --git a/test/decompiler/test_AtomicOpBuilder.cpp b/test/decompiler/test_AtomicOpBuilder.cpp index 4f468fe244..13ac970f28 100644 --- a/test/decompiler/test_AtomicOpBuilder.cpp +++ b/test/decompiler/test_AtomicOpBuilder.cpp @@ -465,13 +465,13 @@ TEST(DecompilerAtomicOpBuilder, LHU) { } TEST(DecompilerAtomicOpBuilder, LUI) { - test_case(assembly_from_list({"lui a3, 2"}), {"(set! a3 131072)"}, {{"a3"}}, {{}}, {{}}); + test_case(assembly_from_list({"lui a3, 2"}), {"(set! a3 #x20000)"}, {{"a3"}}, {{}}, {{}}); } TEST(DecompilerAtomicOpBuilder, LUI_ORI) { - test_case(assembly_from_list({"L100:", "lui a0, 2", "ori a1, a0, 3"}), {"(set! a1 131075)"}, + test_case(assembly_from_list({"L100:", "lui a0, 2", "ori a1, a0, 3"}), {"(set! a1 #x20003)"}, {{"a1"}}, {{}}, {{"a0"}}); - test_case(assembly_from_list({"L100:", "lui a0, 2", "ori a0, a0, 3"}), {"(set! a0 131075)"}, + test_case(assembly_from_list({"L100:", "lui a0, 2", "ori a0, a0, 3"}), {"(set! a0 #x20003)"}, {{"a0"}}, {{}}, {{}}); test_case(assembly_from_list({"L100:", "lui a0, L100", "ori a1, a0, L100"}), {"(set! a1 L100)"}, {{"a1"}}, {{}}, {{"a0"}}); diff --git a/test/test_goos.cpp b/test/test_goos.cpp index a0346bfa10..d67d65a47e 100644 --- a/test/test_goos.cpp +++ b/test/test_goos.cpp @@ -871,7 +871,8 @@ TEST(GoosLib, Desfun) { TEST(GoosLib, Factorial) { Interpreter i; - EXPECT_EQ(e(i, "(factorial 10)"), "3628800"); + // now large numbers are printed as hex. + EXPECT_EQ(e(i, "(factorial 10)"), "#x375f00"); } TEST(GoosLib, ApplySimple) {