mirror of
https://github.com/open-goal/jak-project
synced 2026-06-08 20:29:54 -04:00
Merge pull request #1 from xTVaser/github-actions
Add Github Actions to build / test / lint in a linux environment and format all source-code files
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
name: Linux Workflow
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Test Project (Linux)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Get Package Dependencies
|
||||
run: sudo apt install gcc make cmake build-essential g++ nasm clang-format
|
||||
- name: Initialize Submodules
|
||||
run: git submodule update --init --recursive
|
||||
- name: Build Project with CMake
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j
|
||||
- name: Test Project with gTest
|
||||
run: ./test.sh
|
||||
- name: Check Clang-Formatting
|
||||
run: |
|
||||
chmod +x ./third-party/run-clang-format/run-clang-format.py
|
||||
./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test --color always
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "third-party/googletest"]
|
||||
path = third-party/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
url = https://github.com/google/googletest.git
|
||||
@@ -5,12 +5,6 @@ constexpr int POINTER_SIZE = 4;
|
||||
constexpr int BASIC_OFFSET = 4;
|
||||
constexpr int STRUCTURE_ALIGNMENT = 16;
|
||||
|
||||
enum class RegKind {
|
||||
GPR_64,
|
||||
FLOAT,
|
||||
INT_128,
|
||||
FLOAT_4X,
|
||||
INVALID
|
||||
};
|
||||
enum class RegKind { GPR_64, FLOAT, INT_128, FLOAT_4X, INVALID };
|
||||
|
||||
#endif // JAK_GOAL_CONSTANTS_H
|
||||
|
||||
+62
-61
@@ -6,75 +6,76 @@
|
||||
#ifndef JAK1_SYMBOLS_H
|
||||
#define JAK1_SYMBOLS_H
|
||||
|
||||
constexpr int FIX_SYM_EMPTY_CAR = -0xc;
|
||||
constexpr int FIX_SYM_EMPTY_CAR = -0xc;
|
||||
constexpr int FIX_SYM_EMPTY_PAIR = -0xa;
|
||||
constexpr int FIX_SYM_EMPTY_CDR = -0x8;
|
||||
constexpr int FIX_SYM_FALSE = 0x0; // GOAL boolean #f (note that this is equal to the $s7 register)
|
||||
constexpr int FIX_SYM_TRUE = 0x8; // GOAL boolean #t
|
||||
constexpr int FIX_SYM_EMPTY_CDR = -0x8;
|
||||
constexpr int FIX_SYM_FALSE = 0x0; // GOAL boolean #f (note that this is equal to the $s7 register)
|
||||
constexpr int FIX_SYM_TRUE = 0x8; // GOAL boolean #t
|
||||
|
||||
// types
|
||||
constexpr int FIX_SYM_FUNCTION_TYPE = 0x10; // GOAL type of function
|
||||
constexpr int FIX_SYM_BASIC_TYPE = 0x18; // GOAL structure type with type tag
|
||||
constexpr int FIX_SYM_STRING_TYPE = 0x20; // GOAL string type (gstring)
|
||||
constexpr int FIX_SYM_SYMBOL_TYPE = 0x28; // GOAL symbol type
|
||||
constexpr int FIX_SYM_TYPE_TYPE = 0x30; // GOAL type of type
|
||||
constexpr int FIX_SYM_OBJECT_TYPE = 0x38; // GOAL parent type of all types
|
||||
constexpr int FIX_SYM_LINK_BLOCK = 0x40; // GOAL type of link-block (used by linker, but seems to be unused by GOAL)
|
||||
constexpr int FIX_SYM_INTEGER_TYPE = 0x48; // GOAL integer parent type, assumes unboxed
|
||||
constexpr int FIX_SYM_SINTEGER_TYPE = 0x50; // GOAL signed integer parent type, assumes unboxed
|
||||
constexpr int FIX_SYM_UINTEGER_TYPE = 0x58; // GOAL unsinged integer parent type, assumes unboxed
|
||||
constexpr int FIX_SYM_BINTEGER_TYPE = 0x60; // GOAL "boxed integer" type
|
||||
constexpr int FIX_SYM_INT8_TYPE = 0x68; // GOAL 8-bit signed integer
|
||||
constexpr int FIX_SYM_INT16_TYPE = 0x70; // ...
|
||||
constexpr int FIX_SYM_INT32_TYPE = 0x78; // ...
|
||||
constexpr int FIX_SYM_INT64_TYPE = 0x80; // ...
|
||||
constexpr int FIX_SYM_INT128_TYPE = 0x88; // GOAL 128-bit integer type, behaves strangely
|
||||
constexpr int FIX_SYM_UINT8_TYPE = 0x90; // GOAL 8-bit unsigned integer
|
||||
constexpr int FIX_SYM_UINT16_TYPE = 0x98; // ...
|
||||
constexpr int FIX_SYM_UINT32_TYPE = 0xA0; // ...
|
||||
constexpr int FIX_SYM_UINT64_TYPE = 0xA8; // ...
|
||||
constexpr int FIX_SYM_UINT128_TYPE = 0xB0; // ...
|
||||
constexpr int FIX_SYM_FLOAT_TYPE = 0xB8; // GOAL 32-bit floating point type
|
||||
constexpr int FIX_SYM_PROCESS_TREE_TYPE = 0xC0; // GOAL process-tree type. Used in the gkernel
|
||||
constexpr int FIX_SYM_PROCESS_TYPE = 0xC8; // GOAL process type
|
||||
constexpr int FIX_SYM_THREAD_TYPE = 0xD0; // GOAL thread type
|
||||
constexpr int FIX_SYM_STRUCTURE_TYPE = 0xD8; // GOAL structure type. Any type with fields
|
||||
constexpr int FIX_SYM_PAIR_TYPE = 0xE0; // GOAL pair type
|
||||
constexpr int FIX_SYM_POINTER_TYPE = 0xE8; // GOAL pointer type (32-bit)
|
||||
constexpr int FIX_SYM_NUMBER_TYPE = 0xF0; // GOAL number type (parent of integer/float types)
|
||||
constexpr int FIX_SYM_ARRAY_TYPE = 0xF8; // GOAL array type
|
||||
constexpr int FIX_SYM_VU_FUNCTION_TYPE = 0x100; // GOAL vu-function type
|
||||
constexpr int FIX_SYM_CONNECTABLE_TYPE = 0x108; // GOAL connectable
|
||||
constexpr int FIX_SYM_STACK_FRAME_TYPE = 0x110; // GOAL stack-frame
|
||||
constexpr int FIX_SYM_FILE_STREAM_TYPE = 0x118; // GOAL file-stream
|
||||
constexpr int FIX_SYM_KHEAP = 0x120; // GOAL kheap
|
||||
constexpr int FIX_SYM_FUNCTION_TYPE = 0x10; // GOAL type of function
|
||||
constexpr int FIX_SYM_BASIC_TYPE = 0x18; // GOAL structure type with type tag
|
||||
constexpr int FIX_SYM_STRING_TYPE = 0x20; // GOAL string type (gstring)
|
||||
constexpr int FIX_SYM_SYMBOL_TYPE = 0x28; // GOAL symbol type
|
||||
constexpr int FIX_SYM_TYPE_TYPE = 0x30; // GOAL type of type
|
||||
constexpr int FIX_SYM_OBJECT_TYPE = 0x38; // GOAL parent type of all types
|
||||
constexpr int FIX_SYM_LINK_BLOCK =
|
||||
0x40; // GOAL type of link-block (used by linker, but seems to be unused by GOAL)
|
||||
constexpr int FIX_SYM_INTEGER_TYPE = 0x48; // GOAL integer parent type, assumes unboxed
|
||||
constexpr int FIX_SYM_SINTEGER_TYPE = 0x50; // GOAL signed integer parent type, assumes unboxed
|
||||
constexpr int FIX_SYM_UINTEGER_TYPE = 0x58; // GOAL unsinged integer parent type, assumes unboxed
|
||||
constexpr int FIX_SYM_BINTEGER_TYPE = 0x60; // GOAL "boxed integer" type
|
||||
constexpr int FIX_SYM_INT8_TYPE = 0x68; // GOAL 8-bit signed integer
|
||||
constexpr int FIX_SYM_INT16_TYPE = 0x70; // ...
|
||||
constexpr int FIX_SYM_INT32_TYPE = 0x78; // ...
|
||||
constexpr int FIX_SYM_INT64_TYPE = 0x80; // ...
|
||||
constexpr int FIX_SYM_INT128_TYPE = 0x88; // GOAL 128-bit integer type, behaves strangely
|
||||
constexpr int FIX_SYM_UINT8_TYPE = 0x90; // GOAL 8-bit unsigned integer
|
||||
constexpr int FIX_SYM_UINT16_TYPE = 0x98; // ...
|
||||
constexpr int FIX_SYM_UINT32_TYPE = 0xA0; // ...
|
||||
constexpr int FIX_SYM_UINT64_TYPE = 0xA8; // ...
|
||||
constexpr int FIX_SYM_UINT128_TYPE = 0xB0; // ...
|
||||
constexpr int FIX_SYM_FLOAT_TYPE = 0xB8; // GOAL 32-bit floating point type
|
||||
constexpr int FIX_SYM_PROCESS_TREE_TYPE = 0xC0; // GOAL process-tree type. Used in the gkernel
|
||||
constexpr int FIX_SYM_PROCESS_TYPE = 0xC8; // GOAL process type
|
||||
constexpr int FIX_SYM_THREAD_TYPE = 0xD0; // GOAL thread type
|
||||
constexpr int FIX_SYM_STRUCTURE_TYPE = 0xD8; // GOAL structure type. Any type with fields
|
||||
constexpr int FIX_SYM_PAIR_TYPE = 0xE0; // GOAL pair type
|
||||
constexpr int FIX_SYM_POINTER_TYPE = 0xE8; // GOAL pointer type (32-bit)
|
||||
constexpr int FIX_SYM_NUMBER_TYPE = 0xF0; // GOAL number type (parent of integer/float types)
|
||||
constexpr int FIX_SYM_ARRAY_TYPE = 0xF8; // GOAL array type
|
||||
constexpr int FIX_SYM_VU_FUNCTION_TYPE = 0x100; // GOAL vu-function type
|
||||
constexpr int FIX_SYM_CONNECTABLE_TYPE = 0x108; // GOAL connectable
|
||||
constexpr int FIX_SYM_STACK_FRAME_TYPE = 0x110; // GOAL stack-frame
|
||||
constexpr int FIX_SYM_FILE_STREAM_TYPE = 0x118; // GOAL file-stream
|
||||
constexpr int FIX_SYM_KHEAP = 0x120; // GOAL kheap
|
||||
|
||||
// GOAL functions
|
||||
constexpr int FIX_SYM_NOTHING_FUNC = 0x128; // GOAL nothing-func (does nothing)
|
||||
constexpr int FIX_SYM_DEL_BASIC_FUNC = 0x130; // GOAL delete-basic function
|
||||
constexpr int FIX_SYM_NOTHING_FUNC = 0x128; // GOAL nothing-func (does nothing)
|
||||
constexpr int FIX_SYM_DEL_BASIC_FUNC = 0x130; // GOAL delete-basic function
|
||||
|
||||
// GOAL allocation symbols (?)
|
||||
constexpr int FIX_SYM_STATIC = 0x138; // GOAL 'static
|
||||
constexpr int FIX_SYM_GLOBAL_HEAP = 0x140; // GOAL 'global
|
||||
constexpr int FIX_SYM_DEBUG_HEAP = 0x148; // GOAL 'debug
|
||||
constexpr int FIX_SYM_LOADING_LEVEL = 0x150; // ??
|
||||
constexpr int FIX_SYM_LOADING_PACKAGE = 0x158; // ??
|
||||
constexpr int FIX_SYM_PROCESS_LEVEL_HEAP = 0x160; // ??
|
||||
constexpr int FIX_SYM_STACK = 0x168; // GOAL 'stack
|
||||
constexpr int FIX_SYM_SCRATCH = 0x170; // GOAL 'scratch
|
||||
constexpr int FIX_SYM_STATIC = 0x138; // GOAL 'static
|
||||
constexpr int FIX_SYM_GLOBAL_HEAP = 0x140; // GOAL 'global
|
||||
constexpr int FIX_SYM_DEBUG_HEAP = 0x148; // GOAL 'debug
|
||||
constexpr int FIX_SYM_LOADING_LEVEL = 0x150; // ??
|
||||
constexpr int FIX_SYM_LOADING_PACKAGE = 0x158; // ??
|
||||
constexpr int FIX_SYM_PROCESS_LEVEL_HEAP = 0x160; // ??
|
||||
constexpr int FIX_SYM_STACK = 0x168; // GOAL 'stack
|
||||
constexpr int FIX_SYM_SCRATCH = 0x170; // GOAL 'scratch
|
||||
|
||||
// GOAL random stuff
|
||||
constexpr int FIX_SYM_SCRATCH_TOP = 0x178; // GOAL *scratch-top*
|
||||
constexpr int FIX_SYM_ZERO_FUNC = 0x180; // GOAL zero-func (returns 0x0 in $v0 register)
|
||||
constexpr int FIX_SYM_ASIZE_OF_BASIC_FUNC = 0x188; // GOAL asize-of-basic function
|
||||
constexpr int FIX_SYM_COPY_BASIC_FUNC = 0x190; // GOAL copy-basic function
|
||||
constexpr int FIX_SYM_LEVEL = 0x198; // ??
|
||||
constexpr int FIX_SYM_ART_GROUP = 0x1a0; // ??
|
||||
constexpr int FIX_SYM_TX_PAGE_DIR = 0x1a8; // ??
|
||||
constexpr int FIX_SYM_TX_PAGE = 0x1b0; // ??
|
||||
constexpr int FIX_SYM_SOUND = 0x1b8; // ??
|
||||
constexpr int FIX_SYM_DGO = 0x1c0; // ??
|
||||
constexpr int FIX_SYM_TOP_LEVEL = 0x1c8; // ??
|
||||
constexpr int FIX_FIXED_SYM_END_OFFSET = 0x1d0;
|
||||
constexpr int FIX_SYM_SCRATCH_TOP = 0x178; // GOAL *scratch-top*
|
||||
constexpr int FIX_SYM_ZERO_FUNC = 0x180; // GOAL zero-func (returns 0x0 in $v0 register)
|
||||
constexpr int FIX_SYM_ASIZE_OF_BASIC_FUNC = 0x188; // GOAL asize-of-basic function
|
||||
constexpr int FIX_SYM_COPY_BASIC_FUNC = 0x190; // GOAL copy-basic function
|
||||
constexpr int FIX_SYM_LEVEL = 0x198; // ??
|
||||
constexpr int FIX_SYM_ART_GROUP = 0x1a0; // ??
|
||||
constexpr int FIX_SYM_TX_PAGE_DIR = 0x1a8; // ??
|
||||
constexpr int FIX_SYM_TX_PAGE = 0x1b0; // ??
|
||||
constexpr int FIX_SYM_SOUND = 0x1b8; // ??
|
||||
constexpr int FIX_SYM_DGO = 0x1c0; // ??
|
||||
constexpr int FIX_SYM_TOP_LEVEL = 0x1c8; // ??
|
||||
constexpr int FIX_FIXED_SYM_END_OFFSET = 0x1d0;
|
||||
|
||||
#endif // JAK1_SYMBOLS_H
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef JAK_TYPE_UTIL_H
|
||||
#define JAK_TYPE_UTIL_H
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
T align(T current, T alignment, T offset = 0) {
|
||||
while((current % alignment) != 0) {
|
||||
while ((current % alignment) != 0) {
|
||||
current++;
|
||||
}
|
||||
return current + offset;
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ namespace versions {
|
||||
// language version
|
||||
constexpr s32 GOAL_VERSION_MAJOR = 2;
|
||||
constexpr s32 GOAL_VERSION_MINOR = 6;
|
||||
}
|
||||
} // namespace versions
|
||||
|
||||
// GOAL kernel version
|
||||
constexpr int KERNEL_VERSION_MAJOR = 2;
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
|
||||
struct FunctionName {
|
||||
enum class FunctionKind {
|
||||
UNIDENTIFIED, // hasn't been identified yet.
|
||||
GLOBAL, // global named function
|
||||
UNIDENTIFIED, // hasn't been identified yet.
|
||||
GLOBAL, // global named function
|
||||
METHOD,
|
||||
TOP_LEVEL_INIT,
|
||||
} kind = FunctionKind::UNIDENTIFIED;
|
||||
|
||||
std::string function_name; // only applicable for GLOBAL
|
||||
std::string type_name; // only applicable for METHOD
|
||||
int method_id = -1; // only applicable for METHOD
|
||||
std::string function_name; // only applicable for GLOBAL
|
||||
std::string type_name; // only applicable for METHOD
|
||||
int method_id = -1; // only applicable for METHOD
|
||||
|
||||
std::string to_string() const {
|
||||
switch(kind) {
|
||||
switch (kind) {
|
||||
case FunctionKind::GLOBAL:
|
||||
return function_name;
|
||||
case FunctionKind::METHOD:
|
||||
@@ -34,13 +34,9 @@ struct FunctionName {
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return kind == FunctionKind::UNIDENTIFIED;
|
||||
}
|
||||
bool empty() const { return kind == FunctionKind::UNIDENTIFIED; }
|
||||
|
||||
void set_as_top_level() {
|
||||
kind = FunctionKind::TOP_LEVEL_INIT;
|
||||
}
|
||||
void set_as_top_level() { kind = FunctionKind::TOP_LEVEL_INIT; }
|
||||
|
||||
void set_as_global(std::string name) {
|
||||
kind = FunctionKind::GLOBAL;
|
||||
|
||||
@@ -90,7 +90,7 @@ Function& LinkedObjectFile::get_function_at_label(int label_id) {
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return functions_by_seg.front().front(); // to avoid error
|
||||
return functions_by_seg.front().front(); // to avoid error
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -520,7 +520,7 @@ std::string LinkedObjectFile::print_disassembly() {
|
||||
result += "; .function " + func.guessed_name.to_string() + "\n";
|
||||
result += ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n";
|
||||
result += func.prologue.to_string(2) + "\n";
|
||||
if(!func.warnings.empty()) {
|
||||
if (!func.warnings.empty()) {
|
||||
result += "Warnings: " + func.warnings + "\n";
|
||||
}
|
||||
|
||||
@@ -581,11 +581,11 @@ std::string LinkedObjectFile::print_disassembly() {
|
||||
// }
|
||||
|
||||
// hack
|
||||
if(func.cfg && !func.cfg->is_fully_resolved()) {
|
||||
if (func.cfg && !func.cfg->is_fully_resolved()) {
|
||||
result += func.cfg->to_dot();
|
||||
result += "\n";
|
||||
}
|
||||
if(func.cfg) {
|
||||
if (func.cfg) {
|
||||
result += func.cfg->to_form_string() + "\n";
|
||||
|
||||
// To debug block stuff.
|
||||
@@ -614,7 +614,6 @@ std::string LinkedObjectFile::print_disassembly() {
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
result += "\n\n\n";
|
||||
}
|
||||
|
||||
@@ -636,7 +635,6 @@ std::string LinkedObjectFile::print_disassembly() {
|
||||
|
||||
if (word.kind == LinkedWord::TYPE_PTR && word.symbol_name == "string") {
|
||||
result += "; " + get_goal_string(seg, i) + "\n";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "decompiler/Function/Function.h"
|
||||
#include "decompiler/util/LispPrint.h"
|
||||
|
||||
|
||||
/*!
|
||||
* A label to a location in this object file.
|
||||
* Doesn't have to be word aligned.
|
||||
@@ -23,14 +22,14 @@
|
||||
struct Label {
|
||||
std::string name;
|
||||
int target_segment;
|
||||
int offset; // in bytes
|
||||
int offset; // in bytes
|
||||
};
|
||||
|
||||
/*!
|
||||
* An object file's data with linking information included.
|
||||
*/
|
||||
class LinkedObjectFile {
|
||||
public:
|
||||
public:
|
||||
LinkedObjectFile() = default;
|
||||
void set_segment_count(int n_segs);
|
||||
void push_back_word_to_segment(uint32_t word, int segment);
|
||||
@@ -38,8 +37,15 @@ public:
|
||||
int get_label_at(int seg, int offset) const;
|
||||
bool label_points_to_code(int label_id) const;
|
||||
bool pointer_link_word(int source_segment, int source_offset, int dest_segment, int dest_offset);
|
||||
void pointer_link_split_word(int source_segment, int source_hi_offset, int source_lo_offset, int dest_segment, int dest_offset);
|
||||
void symbol_link_word(int source_segment, int source_offset, const char* name, LinkedWord::Kind kind);
|
||||
void pointer_link_split_word(int source_segment,
|
||||
int source_hi_offset,
|
||||
int source_lo_offset,
|
||||
int dest_segment,
|
||||
int dest_offset);
|
||||
void symbol_link_word(int source_segment,
|
||||
int source_offset,
|
||||
const char* name,
|
||||
LinkedWord::Kind kind);
|
||||
void symbol_link_offset(int source_segment, int source_offset, const char* name);
|
||||
Function& get_function_at_label(int label_id);
|
||||
std::string get_label_name(int label_id) const;
|
||||
@@ -83,7 +89,6 @@ public:
|
||||
uint32_t n_fp_reg_use = 0;
|
||||
uint32_t n_fp_reg_use_resolved = 0;
|
||||
|
||||
|
||||
void add(const Stats& other) {
|
||||
total_code_bytes += other.total_code_bytes;
|
||||
total_v2_code_bytes += other.total_v2_code_bytes;
|
||||
@@ -116,9 +121,9 @@ public:
|
||||
std::vector<std::vector<Function>> functions_by_seg;
|
||||
std::vector<Label> labels;
|
||||
|
||||
private:
|
||||
private:
|
||||
std::shared_ptr<Form> to_form_script(int seg, int word_idx, std::vector<bool>& seen);
|
||||
std::shared_ptr<Form> to_form_script_object(int seg, int byte_idx, std::vector<bool> &seen);
|
||||
std::shared_ptr<Form> to_form_script_object(int seg, int byte_idx, std::vector<bool>& seen);
|
||||
bool is_empty_list(int seg, int byte_idx);
|
||||
bool is_string(int seg, int byte_idx);
|
||||
std::string get_goal_string(int seg, int word_idx);
|
||||
@@ -126,6 +131,4 @@ private:
|
||||
std::vector<std::unordered_map<int, int>> label_per_seg_by_offset;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //NEXT_LINKEDOBJECTFILE_H
|
||||
#endif // NEXT_LINKEDOBJECTFILE_H
|
||||
|
||||
@@ -213,7 +213,6 @@ static uint32_t align16(uint32_t in) {
|
||||
return (in + 15) & (~15);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Process link data for a "V4" object file.
|
||||
* In reality a V4 seems to be just a V2 object, but with the link data after the real data.
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
|
||||
LinkedObjectFile to_linked_object_file(const std::vector<uint8_t>& data, const std::string& name);
|
||||
|
||||
#endif //NEXT_LINKEDOBJECTFILECREATION_H
|
||||
#endif // NEXT_LINKEDOBJECTFILECREATION_H
|
||||
|
||||
@@ -421,8 +421,8 @@ void ObjectFileDB::analyze_functions() {
|
||||
(void)segment_id;
|
||||
auto name = func.guessed_name.to_string();
|
||||
if (func.guessed_name.expected_unique()) {
|
||||
if(unique_names.find(name) != unique_names.end()) {
|
||||
duplicated_functions[name].insert(data.record.to_unique_name());
|
||||
if (unique_names.find(name) != unique_names.end()) {
|
||||
duplicated_functions[name].insert(data.record.to_unique_name());
|
||||
}
|
||||
|
||||
unique_names.insert(name);
|
||||
@@ -435,22 +435,22 @@ void ObjectFileDB::analyze_functions() {
|
||||
});
|
||||
|
||||
for_each_function([&](Function& func, int segment_id, ObjectFileData& data) {
|
||||
(void)segment_id;
|
||||
auto name = func.guessed_name.to_string();
|
||||
if(func.guessed_name.expected_unique()) {
|
||||
if(duplicated_functions.find(name) != duplicated_functions.end()) {
|
||||
duplicated_functions[name].insert(data.record.to_unique_name());
|
||||
func.warnings += "this function exists in multiple non-identical object files";
|
||||
}
|
||||
(void)segment_id;
|
||||
auto name = func.guessed_name.to_string();
|
||||
if (func.guessed_name.expected_unique()) {
|
||||
if (duplicated_functions.find(name) != duplicated_functions.end()) {
|
||||
duplicated_functions[name].insert(data.record.to_unique_name());
|
||||
func.warnings += "this function exists in multiple non-identical object files";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// for(const auto& kv : duplicated_functions) {
|
||||
// printf("Function %s is found in non-identical object files:\n", kv.first.c_str());
|
||||
// for(const auto& obj : kv.second) {
|
||||
// printf(" %s\n", obj.c_str());
|
||||
// }
|
||||
// }
|
||||
// for(const auto& kv : duplicated_functions) {
|
||||
// printf("Function %s is found in non-identical object files:\n", kv.first.c_str());
|
||||
// for(const auto& obj : kv.second) {
|
||||
// printf(" %s\n", obj.c_str());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
int total_nontrivial_functions = 0;
|
||||
@@ -466,45 +466,48 @@ void ObjectFileDB::analyze_functions() {
|
||||
total_basic_blocks += blocks.size();
|
||||
func.basic_blocks = blocks;
|
||||
|
||||
if(!func.suspected_asm) {
|
||||
func.analyze_prologue(data.linked_data);
|
||||
func.cfg = build_cfg(data.linked_data, segment_id, func);
|
||||
total_functions++;
|
||||
if (func.cfg->is_fully_resolved()) {
|
||||
resolved_cfg_functions++;
|
||||
}
|
||||
if (!func.suspected_asm) {
|
||||
func.analyze_prologue(data.linked_data);
|
||||
func.cfg = build_cfg(data.linked_data, segment_id, func);
|
||||
total_functions++;
|
||||
if (func.cfg->is_fully_resolved()) {
|
||||
resolved_cfg_functions++;
|
||||
}
|
||||
} else {
|
||||
resolved_cfg_functions++;
|
||||
}
|
||||
|
||||
|
||||
if(func.basic_blocks.size() > 1 && !func.suspected_asm) {
|
||||
if (func.basic_blocks.size() > 1 && !func.suspected_asm) {
|
||||
total_nontrivial_functions++;
|
||||
if(func.cfg->is_fully_resolved()) {
|
||||
if (func.cfg->is_fully_resolved()) {
|
||||
total_resolved_nontrivial_functions++;
|
||||
} else {
|
||||
if(!func.guessed_name.empty()) {
|
||||
unresolved_by_length[func.end_word - func.start_word].push_back(func.guessed_name.to_string());
|
||||
if (!func.guessed_name.empty()) {
|
||||
unresolved_by_length[func.end_word - func.start_word].push_back(
|
||||
func.guessed_name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!func.guessed_name.empty()) {
|
||||
if (!func.guessed_name.empty()) {
|
||||
total_named_functions++;
|
||||
}
|
||||
});
|
||||
|
||||
printf("Found %d functions (%d with nontrivial cfgs)\n", total_functions, total_nontrivial_functions);
|
||||
printf("Named %d/%d functions (%.2f%%)\n", total_named_functions, total_functions, 100.f * float(total_named_functions) / float(total_functions));
|
||||
printf("Found %d functions (%d with nontrivial cfgs)\n", total_functions,
|
||||
total_nontrivial_functions);
|
||||
printf("Named %d/%d functions (%.2f%%)\n", total_named_functions, total_functions,
|
||||
100.f * float(total_named_functions) / float(total_functions));
|
||||
printf("Found %d basic blocks in %.3f ms\n", total_basic_blocks, timer.getMs());
|
||||
printf(" %d/%d functions passed cfg analysis stage (%.2f%%)\n", resolved_cfg_functions, total_functions,
|
||||
100.f * float(resolved_cfg_functions) / float(total_functions));
|
||||
printf(" %d/%d nontrivial cfg's resolved (%.2f%%)\n", total_resolved_nontrivial_functions, total_nontrivial_functions,
|
||||
printf(" %d/%d functions passed cfg analysis stage (%.2f%%)\n", resolved_cfg_functions,
|
||||
total_functions, 100.f * float(resolved_cfg_functions) / float(total_functions));
|
||||
printf(" %d/%d nontrivial cfg's resolved (%.2f%%)\n", total_resolved_nontrivial_functions,
|
||||
total_nontrivial_functions,
|
||||
100.f * float(total_resolved_nontrivial_functions) / float(total_nontrivial_functions));
|
||||
|
||||
for(auto& kv : unresolved_by_length) {
|
||||
for (auto& kv : unresolved_by_length) {
|
||||
printf("LEN %d\n", kv.first);
|
||||
for(auto& x : kv.second) {
|
||||
for (auto& x : kv.second) {
|
||||
printf(" %s\n", x.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ class ObjectFileDB {
|
||||
template <typename Func>
|
||||
void for_each_obj(Func f) {
|
||||
assert(obj_files_by_name.size() == obj_file_order.size());
|
||||
for(const auto& name : obj_file_order) {
|
||||
for(auto& obj : obj_files_by_name.at(name)) {
|
||||
for (const auto& name : obj_file_order) {
|
||||
for (auto& obj : obj_files_by_name.at(name)) {
|
||||
f(obj);
|
||||
}
|
||||
}
|
||||
@@ -75,12 +75,12 @@ class ObjectFileDB {
|
||||
template <typename Func>
|
||||
void for_each_function(Func f) {
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
// printf("IN %s\n", data.record.to_unique_name().c_str());
|
||||
// printf("IN %s\n", data.record.to_unique_name().c_str());
|
||||
for (int i = 0; i < int(data.linked_data.segments); i++) {
|
||||
// printf("seg %d\n", i);
|
||||
// printf("seg %d\n", i);
|
||||
int fn = 0;
|
||||
for (auto& goal_func : data.linked_data.functions_by_seg.at(i)) {
|
||||
// printf("fn %d\n", fn);
|
||||
// printf("fn %d\n", fn);
|
||||
f(goal_func, i, data);
|
||||
fn++;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
class GoalFunction {
|
||||
public:
|
||||
// enum Kind {
|
||||
// GLOBAL_FUNCTION,
|
||||
// ANON_FUNCTION,
|
||||
// METHOD,
|
||||
// BEHAVIOR,
|
||||
// UNKNOWN
|
||||
// };
|
||||
// enum Kind {
|
||||
// GLOBAL_FUNCTION,
|
||||
// ANON_FUNCTION,
|
||||
// METHOD,
|
||||
// BEHAVIOR,
|
||||
// UNKNOWN
|
||||
// };
|
||||
};
|
||||
|
||||
#endif // JAK_DISASSEMBLER_GOALFUNCTION_H
|
||||
|
||||
@@ -13,14 +13,13 @@ class GoalSymbol {
|
||||
m_has_type_info = true;
|
||||
}
|
||||
|
||||
bool has_type_info() const {
|
||||
return m_has_type_info;
|
||||
}
|
||||
bool has_type_info() const { return m_has_type_info; }
|
||||
|
||||
void set_type(TypeSpec ts) {
|
||||
if(m_has_type_info) {
|
||||
if(ts != m_type) {
|
||||
printf("symbol %s %s -> %s", m_name.c_str(), m_type.to_string().c_str(), ts.to_string().c_str());
|
||||
if (m_has_type_info) {
|
||||
if (ts != m_type) {
|
||||
printf("symbol %s %s -> %s", m_name.c_str(), m_type.to_string().c_str(),
|
||||
ts.to_string().c_str());
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,10 @@
|
||||
class GoalType {
|
||||
public:
|
||||
GoalType() = default;
|
||||
GoalType(std::string name) : m_name(std::move(name)) { }
|
||||
bool has_info() const {
|
||||
return m_has_info;
|
||||
}
|
||||
GoalType(std::string name) : m_name(std::move(name)) {}
|
||||
bool has_info() const { return m_has_info; }
|
||||
|
||||
bool has_method_count() const {
|
||||
return m_method_count_set;
|
||||
}
|
||||
bool has_method_count() const { return m_method_count_set; }
|
||||
|
||||
void set_methods(int n);
|
||||
|
||||
|
||||
@@ -48,9 +48,10 @@ std::string TypeInfo::get_summary() {
|
||||
" Total Types: %d\n"
|
||||
" with info: %d (%.2f%%)\n"
|
||||
" with method count: %d (%.2f%%)\n",
|
||||
total_symbols, syms_with_type_info, 100.f * float(syms_with_type_info) / float(total_symbols),
|
||||
total_types, types_with_info, 100.f * float(types_with_info) / float(total_types),
|
||||
types_with_method_count, 100.f * float(types_with_method_count) / float(total_types));
|
||||
total_symbols, syms_with_type_info,
|
||||
100.f * float(syms_with_type_info) / float(total_symbols), total_types, types_with_info,
|
||||
100.f * float(types_with_info) / float(total_types), types_with_method_count,
|
||||
100.f * float(types_with_method_count) / float(total_types));
|
||||
|
||||
return {buffer};
|
||||
}
|
||||
@@ -67,7 +68,7 @@ void TypeInfo::inform_symbol_with_no_type_info(const std::string& name) {
|
||||
}
|
||||
}
|
||||
|
||||
void TypeInfo::inform_symbol(const std::string &name, TypeSpec type) {
|
||||
void TypeInfo::inform_symbol(const std::string& name, TypeSpec type) {
|
||||
inform_symbol_with_no_type_info(name);
|
||||
m_symbols.at(name).set_type(std::move(type));
|
||||
}
|
||||
@@ -88,10 +89,10 @@ void TypeInfo::inform_type_method_count(const std::string& name, int methods) {
|
||||
|
||||
std::string TypeInfo::get_all_symbols_debug() {
|
||||
std::string result = "const char* all_syms[" + std::to_string(m_symbols.size()) + "] = {";
|
||||
for(auto& x : m_symbols) {
|
||||
for (auto& x : m_symbols) {
|
||||
result += "\"" + x.first + "\",";
|
||||
}
|
||||
if(!result.empty()) {
|
||||
if (!result.empty()) {
|
||||
result.pop_back();
|
||||
}
|
||||
return result + "};";
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
class TypeSpec {
|
||||
public:
|
||||
TypeSpec() = default;
|
||||
explicit TypeSpec(std::string base_type) : m_base_type(std::move(base_type)) { }
|
||||
TypeSpec(std::string base_type, std::vector<TypeSpec> args) : m_base_type(std::move(base_type)), m_args(std::move(args)) { }
|
||||
explicit TypeSpec(std::string base_type) : m_base_type(std::move(base_type)) {}
|
||||
TypeSpec(std::string base_type, std::vector<TypeSpec> args)
|
||||
: m_base_type(std::move(base_type)), m_args(std::move(args)) {}
|
||||
|
||||
std::string to_string() const;
|
||||
std::shared_ptr<Form> to_form() const;
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
printf("%s\n", get_type_info().get_summary().c_str());
|
||||
// printf("%d\n", InstructionKind::EE_OP_MAX);
|
||||
// printf("%s\n", get_type_info().get_all_symbols_debug().c_str());
|
||||
// printf("%d\n", InstructionKind::EE_OP_MAX);
|
||||
// printf("%s\n", get_type_info().get_all_symbols_debug().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
#include <vector>
|
||||
|
||||
class BinaryReader {
|
||||
public:
|
||||
BinaryReader(uint8_t* _buffer, uint32_t _size) : buffer(_buffer), size(_size) {
|
||||
public:
|
||||
BinaryReader(uint8_t* _buffer, uint32_t _size) : buffer(_buffer), size(_size) {}
|
||||
|
||||
}
|
||||
explicit BinaryReader(std::vector<uint8_t>& _buffer)
|
||||
: buffer((uint8_t*)_buffer.data()), size(_buffer.size()) {}
|
||||
|
||||
explicit BinaryReader(std::vector<uint8_t>& _buffer) : buffer((uint8_t*)_buffer.data()), size(_buffer.size()) { }
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
T read() {
|
||||
assert(seek + sizeof(T) <= size);
|
||||
T& obj = *(T*)(buffer + seek);
|
||||
@@ -26,23 +25,16 @@ public:
|
||||
assert(seek <= size);
|
||||
}
|
||||
|
||||
uint32_t bytes_left() const {
|
||||
return size - seek;
|
||||
}
|
||||
uint32_t bytes_left() const { return size - seek; }
|
||||
|
||||
uint8_t* here() {
|
||||
return buffer + seek;
|
||||
}
|
||||
uint8_t* here() { return buffer + seek; }
|
||||
|
||||
uint32_t get_seek() {
|
||||
return seek;
|
||||
}
|
||||
uint32_t get_seek() { return seek; }
|
||||
|
||||
private:
|
||||
private:
|
||||
uint8_t* buffer;
|
||||
uint32_t size;
|
||||
uint32_t seek = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif //JAK_V2_BINARYREADER_H
|
||||
#endif // JAK_V2_BINARYREADER_H
|
||||
|
||||
@@ -16,7 +16,8 @@ std::string combine_path(const std::string& parent, const std::string& child) {
|
||||
|
||||
std::vector<uint8_t> read_binary_file(const std::string& filename) {
|
||||
auto fp = fopen(filename.c_str(), "rb");
|
||||
if(!fp) throw std::runtime_error("File " + filename + " cannot be opened");
|
||||
if (!fp)
|
||||
throw std::runtime_error("File " + filename + " cannot be opened");
|
||||
fseek(fp, 0, SEEK_END);
|
||||
auto len = ftell(fp);
|
||||
rewind(fp);
|
||||
@@ -24,7 +25,7 @@ std::vector<uint8_t> read_binary_file(const std::string& filename) {
|
||||
std::vector<uint8_t> data;
|
||||
data.resize(len);
|
||||
|
||||
if(fread(data.data(), len, 1, fp) != 1) {
|
||||
if (fread(data.data(), len, 1, fp) != 1) {
|
||||
throw std::runtime_error("File " + filename + " cannot be read");
|
||||
}
|
||||
|
||||
@@ -34,8 +35,8 @@ std::vector<uint8_t> read_binary_file(const std::string& filename) {
|
||||
std::string base_name(const std::string& filename) {
|
||||
size_t pos = 0;
|
||||
assert(!filename.empty());
|
||||
for(size_t i = filename.size() - 1; i-- > 0;) {
|
||||
if(filename.at(i) == '/') {
|
||||
for (size_t i = filename.size() - 1; i-- > 0;) {
|
||||
if (filename.at(i) == '/') {
|
||||
pos = (i + 1);
|
||||
break;
|
||||
}
|
||||
@@ -66,14 +67,13 @@ uint32_t crc32(const uint8_t* data, size_t size) {
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
|
||||
uint32_t crc32(const std::vector<uint8_t>& data) {
|
||||
return crc32(data.data(), data.size());
|
||||
}
|
||||
|
||||
void write_text_file(const std::string& file_name, const std::string& text) {
|
||||
FILE* fp = fopen(file_name.c_str(), "w");
|
||||
if(!fp) {
|
||||
if (!fp) {
|
||||
printf("Failed to fopen %s\n", file_name.c_str());
|
||||
throw std::runtime_error("Failed to open file");
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@ void init_crc();
|
||||
uint32_t crc32(const uint8_t* data, size_t size);
|
||||
uint32_t crc32(const std::vector<uint8_t>& data);
|
||||
|
||||
#endif //JAK_V2_FILEIO_H
|
||||
#endif // JAK_V2_FILEIO_H
|
||||
|
||||
@@ -45,11 +45,11 @@ std::string Form::toStringSimple() {
|
||||
return result;
|
||||
}
|
||||
|
||||
void Form::buildStringSimple(std::string &str) {
|
||||
void Form::buildStringSimple(std::string& str) {
|
||||
std::vector<FormToken> tokens;
|
||||
toTokenList(tokens);
|
||||
for(auto& token : tokens) {
|
||||
switch(token.kind) {
|
||||
for (auto& token : tokens) {
|
||||
switch (token.kind) {
|
||||
case TokenKind::WHITESPACE:
|
||||
str.push_back(' ');
|
||||
break;
|
||||
@@ -77,26 +77,25 @@ void Form::buildStringSimple(std::string &str) {
|
||||
}
|
||||
}
|
||||
|
||||
void Form::toTokenList(std::vector<FormToken> &tokens) {
|
||||
switch(kind) {
|
||||
void Form::toTokenList(std::vector<FormToken>& tokens) {
|
||||
switch (kind) {
|
||||
case FormKind::SYMBOL:
|
||||
tokens.emplace_back(TokenKind::SYMBOL, symbol);
|
||||
break;
|
||||
case FormKind::PAIR:
|
||||
{
|
||||
case FormKind::PAIR: {
|
||||
tokens.emplace_back(TokenKind::OPEN_PAREN);
|
||||
Form* toPrint = this;
|
||||
for(;;) {
|
||||
if(toPrint->kind == FormKind::PAIR) {
|
||||
toPrint->pair[0]->toTokenList(tokens); // print CAR
|
||||
for (;;) {
|
||||
if (toPrint->kind == FormKind::PAIR) {
|
||||
toPrint->pair[0]->toTokenList(tokens); // print CAR
|
||||
toPrint = toPrint->pair[1].get();
|
||||
if(toPrint->kind == FormKind::EMPTY_LIST) {
|
||||
if (toPrint->kind == FormKind::EMPTY_LIST) {
|
||||
tokens.emplace_back(TokenKind::CLOSE_PAREN);
|
||||
return;
|
||||
} else {
|
||||
tokens.emplace_back(TokenKind::WHITESPACE);
|
||||
}
|
||||
} else { // not a proper list!
|
||||
} else { // not a proper list!
|
||||
tokens.emplace_back(TokenKind::DOT);
|
||||
tokens.emplace_back(TokenKind::WHITESPACE);
|
||||
toPrint->toTokenList(tokens);
|
||||
@@ -104,8 +103,7 @@ void Form::toTokenList(std::vector<FormToken> &tokens) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case FormKind::EMPTY_LIST:
|
||||
tokens.emplace_back(TokenKind::EMPTY_PAIR);
|
||||
break;
|
||||
@@ -123,25 +121,25 @@ void Form::toTokenList(std::vector<FormToken> &tokens) {
|
||||
* Linked list node representing a token in the output (whitespace, paren, newline, etc)
|
||||
*/
|
||||
struct PrettyPrinterNode {
|
||||
FormToken* tok = nullptr; // if we aren't a newline, we will have a token.
|
||||
int line = -1; // line that token occurs on. undef for newlines
|
||||
int lineIndent = -1; // indent of line. only valid for first token in the line
|
||||
int offset = -1; // offset of beginning of token from left margin
|
||||
FormToken* tok = nullptr; // if we aren't a newline, we will have a token.
|
||||
int line = -1; // line that token occurs on. undef for newlines
|
||||
int lineIndent = -1; // indent of line. only valid for first token in the line
|
||||
int offset = -1; // offset of beginning of token from left margin
|
||||
int specialIndentDelta = 0;
|
||||
bool is_line_separator = false; // true if line separator (not a token)
|
||||
PrettyPrinterNode *next = nullptr, *prev = nullptr; // linked list
|
||||
PrettyPrinterNode *paren = nullptr; // pointer to open paren if in parens. open paren points to close and vice versa
|
||||
explicit PrettyPrinterNode(FormToken& _tok) {
|
||||
tok = &_tok;
|
||||
}
|
||||
bool is_line_separator = false; // true if line separator (not a token)
|
||||
PrettyPrinterNode *next = nullptr, *prev = nullptr; // linked list
|
||||
PrettyPrinterNode* paren =
|
||||
nullptr; // pointer to open paren if in parens. open paren points to close and vice versa
|
||||
explicit PrettyPrinterNode(FormToken& _tok) { tok = &_tok; }
|
||||
PrettyPrinterNode() = default;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Splice in a line break after the given node, it there isn't one already and if it isn't the last node.
|
||||
* Splice in a line break after the given node, it there isn't one already and if it isn't the last
|
||||
* node.
|
||||
*/
|
||||
static void insertNewlineAfter(PrettyPrinterNode* node, int specialIndentDelta) {
|
||||
if(node->next && !node->next->is_line_separator) {
|
||||
if (node->next && !node->next->is_line_separator) {
|
||||
auto* nl = new PrettyPrinterNode;
|
||||
auto* next = node->next;
|
||||
node->next = nl;
|
||||
@@ -154,10 +152,11 @@ static void insertNewlineAfter(PrettyPrinterNode* node, int specialIndentDelta)
|
||||
}
|
||||
|
||||
/*!
|
||||
* Splice in a line break before the given node, if there isn't one already and if it isn't the first node.
|
||||
* Splice in a line break before the given node, if there isn't one already and if it isn't the
|
||||
* first node.
|
||||
*/
|
||||
static void insertNewlineBefore(PrettyPrinterNode* node, int specialIndentDelta) {
|
||||
if(node->prev && !node->prev->is_line_separator) {
|
||||
if (node->prev && !node->prev->is_line_separator) {
|
||||
auto* nl = new PrettyPrinterNode;
|
||||
auto* prev = node->prev;
|
||||
prev->next = nl;
|
||||
@@ -178,13 +177,13 @@ static void breakList(PrettyPrinterNode* leftParen) {
|
||||
auto* rp = leftParen->paren;
|
||||
assert(rp->tok->kind == TokenKind::CLOSE_PAREN);
|
||||
|
||||
for(auto* n = leftParen->next; n && n != rp; n = n->next) {
|
||||
if(!n->is_line_separator) {
|
||||
if(n->tok->kind == TokenKind::OPEN_PAREN) {
|
||||
for (auto* n = leftParen->next; n && n != rp; n = n->next) {
|
||||
if (!n->is_line_separator) {
|
||||
if (n->tok->kind == TokenKind::OPEN_PAREN) {
|
||||
n = n->paren;
|
||||
assert(n->tok->kind == TokenKind::CLOSE_PAREN);
|
||||
insertNewlineAfter(n, 0);
|
||||
} else if(n->tok->kind != TokenKind::WHITESPACE) {
|
||||
} else if (n->tok->kind != TokenKind::WHITESPACE) {
|
||||
assert(n->tok->kind != TokenKind::CLOSE_PAREN);
|
||||
insertNewlineAfter(n, 0);
|
||||
}
|
||||
@@ -200,19 +199,19 @@ static PrettyPrinterNode* propagatePretty(PrettyPrinterNode* list, int line_leng
|
||||
// propagate line numbers
|
||||
PrettyPrinterNode* rv = nullptr;
|
||||
int line = list->line;
|
||||
for(auto* n = list; n; n = n->next) {
|
||||
if(n->is_line_separator) {
|
||||
for (auto* n = list; n; n = n->next) {
|
||||
if (n->is_line_separator) {
|
||||
line++;
|
||||
} else {
|
||||
n->line = line;
|
||||
// add the weird newline.
|
||||
if(n->tok->kind == TokenKind::CLOSE_PAREN) {
|
||||
if(n->line != n->paren->line) {
|
||||
if(n->prev && !n->prev->is_line_separator) {
|
||||
if (n->tok->kind == TokenKind::CLOSE_PAREN) {
|
||||
if (n->line != n->paren->line) {
|
||||
if (n->prev && !n->prev->is_line_separator) {
|
||||
insertNewlineBefore(n, 0);
|
||||
line++;
|
||||
}
|
||||
if(n->next && !n->next->is_line_separator) {
|
||||
if (n->next && !n->next->is_line_separator) {
|
||||
insertNewlineAfter(n, 0);
|
||||
}
|
||||
}
|
||||
@@ -226,12 +225,12 @@ static PrettyPrinterNode* propagatePretty(PrettyPrinterNode* list, int line_leng
|
||||
int offset = 0;
|
||||
PrettyPrinterNode* line_start = list;
|
||||
bool previous_line_sep = false;
|
||||
for(auto* n = list; n; n = n->next) {
|
||||
if(n->is_line_separator) {
|
||||
for (auto* n = list; n; n = n->next) {
|
||||
if (n->is_line_separator) {
|
||||
previous_line_sep = true;
|
||||
offset = indentStack.back() += n->specialIndentDelta;
|
||||
} else {
|
||||
if(previous_line_sep) {
|
||||
if (previous_line_sep) {
|
||||
line_start = n;
|
||||
n->lineIndent = offset;
|
||||
previous_line_sep = false;
|
||||
@@ -239,21 +238,20 @@ static PrettyPrinterNode* propagatePretty(PrettyPrinterNode* list, int line_leng
|
||||
|
||||
n->offset = offset;
|
||||
offset += n->tok->toString().length();
|
||||
if(offset > line_length && !rv) rv = line_start;
|
||||
if(n->tok->kind == TokenKind::OPEN_PAREN) {
|
||||
if(!n->prev || n->prev->is_line_separator) {
|
||||
if (offset > line_length && !rv)
|
||||
rv = line_start;
|
||||
if (n->tok->kind == TokenKind::OPEN_PAREN) {
|
||||
if (!n->prev || n->prev->is_line_separator) {
|
||||
indentStack.push_back(offset + 1);
|
||||
} else {
|
||||
indentStack.push_back(offset - 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(n->tok->kind == TokenKind::CLOSE_PAREN) {
|
||||
if (n->tok->kind == TokenKind::CLOSE_PAREN) {
|
||||
indentStack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -264,9 +262,9 @@ static PrettyPrinterNode* propagatePretty(PrettyPrinterNode* list, int line_leng
|
||||
static PrettyPrinterNode* getNextLine(PrettyPrinterNode* start) {
|
||||
assert(!start->is_line_separator);
|
||||
int line = start->line;
|
||||
for(;;) {
|
||||
if(start->is_line_separator || start->line == line) {
|
||||
if(start->next)
|
||||
for (;;) {
|
||||
if (start->is_line_separator || start->line == line) {
|
||||
if (start->next)
|
||||
start = start->next;
|
||||
else
|
||||
return nullptr;
|
||||
@@ -278,32 +276,37 @@ static PrettyPrinterNode* getNextLine(PrettyPrinterNode* start) {
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get the next open paren on the current line (can start in the middle of line, not inclusive of start)
|
||||
* nullptr if there's no open parens on the rest of this line.
|
||||
* Get the next open paren on the current line (can start in the middle of line, not inclusive of
|
||||
* start) nullptr if there's no open parens on the rest of this line.
|
||||
*/
|
||||
static PrettyPrinterNode* getNextListOnLine(PrettyPrinterNode* start) {
|
||||
int line = start->line;
|
||||
assert(!start->is_line_separator);
|
||||
if(!start->next || start->next->is_line_separator) return nullptr;
|
||||
if (!start->next || start->next->is_line_separator)
|
||||
return nullptr;
|
||||
start = start->next;
|
||||
while(!start->is_line_separator && start->line == line) {
|
||||
if(start->tok->kind == TokenKind::OPEN_PAREN) return start;
|
||||
if(!start->next) return nullptr;
|
||||
while (!start->is_line_separator && start->line == line) {
|
||||
if (start->tok->kind == TokenKind::OPEN_PAREN)
|
||||
return start;
|
||||
if (!start->next)
|
||||
return nullptr;
|
||||
start = start->next;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get the first open paren on the current line (can start in the middle of line, inclusive of start)
|
||||
* nullptr if there's no open parens on the rest of this line
|
||||
* Get the first open paren on the current line (can start in the middle of line, inclusive of
|
||||
* start) nullptr if there's no open parens on the rest of this line
|
||||
*/
|
||||
static PrettyPrinterNode* getFirstListOnLine(PrettyPrinterNode* start) {
|
||||
int line = start->line;
|
||||
assert(!start->is_line_separator);
|
||||
while(!start->is_line_separator && start->line == line) {
|
||||
if(start->tok->kind == TokenKind::OPEN_PAREN) return start;
|
||||
if(!start->next) return nullptr;
|
||||
while (!start->is_line_separator && start->line == line) {
|
||||
if (start->tok->kind == TokenKind::OPEN_PAREN)
|
||||
return start;
|
||||
if (!start->next)
|
||||
return nullptr;
|
||||
start = start->next;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -316,19 +319,19 @@ static PrettyPrinterNode* getFirstBadLine(PrettyPrinterNode* start, int line_len
|
||||
assert(!start->is_line_separator);
|
||||
int currentLine = start->line;
|
||||
auto* currentLineNode = start;
|
||||
for(;;) {
|
||||
if(start->is_line_separator) {
|
||||
for (;;) {
|
||||
if (start->is_line_separator) {
|
||||
assert(start->next);
|
||||
start = start->next;
|
||||
} else {
|
||||
if(start->line != currentLine) {
|
||||
if (start->line != currentLine) {
|
||||
currentLine = start->line;
|
||||
currentLineNode = start;
|
||||
}
|
||||
if(start->offset > line_length) {
|
||||
if (start->offset > line_length) {
|
||||
return currentLineNode;
|
||||
}
|
||||
if(!start->next) {
|
||||
if (!start->next) {
|
||||
return nullptr;
|
||||
}
|
||||
start = start->next;
|
||||
@@ -344,55 +347,54 @@ static void insertBreaksAsNeeded(PrettyPrinterNode* head, int line_length) {
|
||||
PrettyPrinterNode* line_to_start_line_search = head;
|
||||
|
||||
// loop over lines
|
||||
for(;;) {
|
||||
|
||||
for (;;) {
|
||||
// compute lines as needed
|
||||
propagatePretty(head, line_length);
|
||||
|
||||
// search for a bad line starting at the last line we fixed
|
||||
PrettyPrinterNode* candidate_line = getFirstBadLine(line_to_start_line_search, line_length);
|
||||
// if we got the same line we started on, this means we couldn't fix it.
|
||||
if(candidate_line == last_line_complete) {
|
||||
candidate_line = nullptr; // so we say our candidate was bad and try to find another
|
||||
if (candidate_line == last_line_complete) {
|
||||
candidate_line = nullptr; // so we say our candidate was bad and try to find another
|
||||
PrettyPrinterNode* next_line = getNextLine(line_to_start_line_search);
|
||||
if(next_line) {
|
||||
if (next_line) {
|
||||
candidate_line = getFirstBadLine(next_line, line_length);
|
||||
}
|
||||
}
|
||||
if(!candidate_line) break;
|
||||
if (!candidate_line)
|
||||
break;
|
||||
|
||||
// okay, we have a line which needs fixing.
|
||||
assert(!candidate_line->prev || candidate_line->prev->is_line_separator);
|
||||
PrettyPrinterNode* form_to_start = getFirstListOnLine(candidate_line);
|
||||
for(;;) {
|
||||
if(!form_to_start) {
|
||||
for (;;) {
|
||||
if (!form_to_start) {
|
||||
printf("pretty printer has failed. Fix the bug or increase the the line length.\n");
|
||||
assert(false);
|
||||
}
|
||||
breakList(form_to_start);
|
||||
propagatePretty(head, line_length);
|
||||
if(getFirstBadLine(candidate_line, line_length) != candidate_line) {
|
||||
if (getFirstBadLine(candidate_line, line_length) != candidate_line) {
|
||||
break;
|
||||
}
|
||||
|
||||
form_to_start = getNextListOnLine(form_to_start);
|
||||
if(!form_to_start) break;
|
||||
|
||||
if (!form_to_start)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
last_line_complete = candidate_line;
|
||||
line_to_start_line_search = candidate_line;
|
||||
}
|
||||
}
|
||||
|
||||
static void insertSpecialBreaks(PrettyPrinterNode* node) {
|
||||
for(; node; node = node->next) {
|
||||
if(!node->is_line_separator && node->tok->kind == TokenKind::SYMBOL) {
|
||||
for (; node; node = node->next) {
|
||||
if (!node->is_line_separator && node->tok->kind == TokenKind::SYMBOL) {
|
||||
std::string& name = *node->tok->str;
|
||||
if(name == "deftype") {
|
||||
if (name == "deftype") {
|
||||
auto* parent_type_dec = getNextListOnLine(node);
|
||||
if(parent_type_dec) {
|
||||
if (parent_type_dec) {
|
||||
insertNewlineAfter(parent_type_dec->paren, 0);
|
||||
}
|
||||
}
|
||||
@@ -415,7 +417,7 @@ std::string Form::toStringPretty(int indent, int line_length) {
|
||||
head->offset = 0;
|
||||
head->lineIndent = 0;
|
||||
int offset = head->tok->toString().length();
|
||||
for(size_t i = 1; i < tokens.size(); i++) {
|
||||
for (size_t i = 1; i < tokens.size(); i++) {
|
||||
node->next = new PrettyPrinterNode(tokens[i]);
|
||||
node->next->prev = node;
|
||||
node = node->next;
|
||||
@@ -428,10 +430,10 @@ std::string Form::toStringPretty(int indent, int line_length) {
|
||||
// attach parens.
|
||||
std::vector<PrettyPrinterNode*> parenStack;
|
||||
parenStack.push_back(nullptr);
|
||||
for(PrettyPrinterNode* n = head; n; n = n->next) {
|
||||
if(n->tok->kind == TokenKind::OPEN_PAREN) {
|
||||
for (PrettyPrinterNode* n = head; n; n = n->next) {
|
||||
if (n->tok->kind == TokenKind::OPEN_PAREN) {
|
||||
parenStack.push_back(n);
|
||||
} else if(n->tok->kind == TokenKind::CLOSE_PAREN) {
|
||||
} else if (n->tok->kind == TokenKind::CLOSE_PAREN) {
|
||||
n->paren = parenStack.back();
|
||||
parenStack.back()->paren = n;
|
||||
parenStack.pop_back();
|
||||
@@ -446,31 +448,31 @@ std::string Form::toStringPretty(int indent, int line_length) {
|
||||
propagatePretty(head, line_length);
|
||||
insertBreaksAsNeeded(head, line_length);
|
||||
|
||||
|
||||
// write to string
|
||||
bool newline_prev = true;
|
||||
for(PrettyPrinterNode* n = head; n; n = n->next) {
|
||||
if(n->is_line_separator){
|
||||
for (PrettyPrinterNode* n = head; n; n = n->next) {
|
||||
if (n->is_line_separator) {
|
||||
pretty.push_back('\n');
|
||||
newline_prev = true;
|
||||
} else {
|
||||
if(newline_prev) {
|
||||
if (newline_prev) {
|
||||
pretty.append(n->lineIndent, ' ');
|
||||
newline_prev = false;
|
||||
if(n->tok->kind == TokenKind::WHITESPACE) continue;
|
||||
if (n->tok->kind == TokenKind::WHITESPACE)
|
||||
continue;
|
||||
}
|
||||
pretty.append(n->tok->toString());
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if(!head) break;
|
||||
for (;;) {
|
||||
if (!head)
|
||||
break;
|
||||
auto* next = head->next;
|
||||
delete head;
|
||||
head = next;
|
||||
}
|
||||
|
||||
|
||||
return pretty;
|
||||
}
|
||||
|
||||
@@ -497,7 +499,7 @@ std::shared_ptr<Form> buildList(std::shared_ptr<Form>* forms, int count) {
|
||||
auto f = std::make_shared<Form>();
|
||||
f->kind = FormKind::PAIR;
|
||||
f->pair[0] = forms[0];
|
||||
if(count - 1) {
|
||||
if (count - 1) {
|
||||
f->pair[1] = buildList(forms + 1, count - 1);
|
||||
} else {
|
||||
f->pair[1] = gSymbolTable.getEmptyPair();
|
||||
@@ -507,7 +509,7 @@ std::shared_ptr<Form> buildList(std::shared_ptr<Form>* forms, int count) {
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> buildList(std::vector<std::shared_ptr<Form>>& forms) {
|
||||
if(forms.empty()) {
|
||||
if (forms.empty()) {
|
||||
return gSymbolTable.getEmptyPair();
|
||||
}
|
||||
return buildList(forms.data(), forms.size());
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Memory card interface. Very messy code.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JAK_KMEMCARD_H
|
||||
#define JAK_KMEMCARD_H
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
#include "common/versions.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
while(true) {
|
||||
while (true) {
|
||||
// run the runtime in a loop so we can reset the game and have it restart cleanly
|
||||
printf("gk %d.%d\n", versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR);
|
||||
exec_runtime(argc, argv);
|
||||
|
||||
@@ -76,7 +76,7 @@ void DMA_SendToEE(void* data, u32 size, void* dest) {
|
||||
|
||||
if (dmaid == 0) {
|
||||
do {
|
||||
printf("Got a bad DMA ID!\n"); // added
|
||||
printf("Got a bad DMA ID!\n"); // added
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,13 +80,13 @@ static const char* next_dir = nullptr;
|
||||
int FS_Init(u8* buffer) {
|
||||
(void)buffer;
|
||||
// get path to next/. Will be set in the gk.sh launch script.
|
||||
next_dir = std::getenv("NEXT_DIR"); // todo windows?
|
||||
next_dir = std::getenv("NEXT_DIR"); // todo windows?
|
||||
assert(next_dir);
|
||||
|
||||
// get path to next/data/fake_iso.txt, the map file.
|
||||
char fakeiso_path[512];
|
||||
strcpy(fakeiso_path, next_dir);
|
||||
strcat(fakeiso_path, "/game/fake_iso.txt"); // todo windows paths?
|
||||
strcat(fakeiso_path, "/game/fake_iso.txt"); // todo windows paths?
|
||||
|
||||
// open the map.
|
||||
FILE* fp = fopen(fakeiso_path, "r");
|
||||
@@ -325,7 +325,7 @@ uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len) {
|
||||
*/
|
||||
uint32_t FS_SyncRead() {
|
||||
// FS_BeginRead is blocking, so this is useless.
|
||||
if(read_in_progress) {
|
||||
if (read_in_progress) {
|
||||
read_in_progress = false;
|
||||
return CMD_STATUS_IN_PROGRESS;
|
||||
} else {
|
||||
|
||||
@@ -17,4 +17,4 @@
|
||||
void fake_iso_init_globals();
|
||||
extern IsoFs fake_iso;
|
||||
|
||||
#endif //JAK_V2_FAKE_ISO_H
|
||||
#endif // JAK_V2_FAKE_ISO_H
|
||||
|
||||
@@ -767,7 +767,6 @@ u32 ProcessVAGData(IsoMessage* _cmd, IsoBufferHeader* buffer_header) {
|
||||
// TODO - UpdatePlayPos
|
||||
// TODO - CheckVAGStreamProgress
|
||||
|
||||
|
||||
void* RPC_DGO(unsigned int fno, void* _cmd, int y);
|
||||
void LoadDGO(RPC_Dgo_Cmd* cmd);
|
||||
void LoadNextDGO(RPC_Dgo_Cmd* cmd);
|
||||
@@ -913,7 +912,7 @@ void CancelDGO(RPC_Dgo_Cmd* cmd) {
|
||||
SendMbx(sync_mbx, nullptr);
|
||||
// wait for it to abort.
|
||||
WaitMbx(dgo_mbx);
|
||||
assert(cmd); // bug
|
||||
assert(cmd); // bug
|
||||
cmd->result = DGO_RPC_RESULT_ABORTED;
|
||||
scmd.cmd_id = 0;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using namespace iop;
|
||||
/*!
|
||||
* Load a File to IOP memory (blocking)
|
||||
*/
|
||||
void LoadISOFileToIOP(FileRecord *file, void *addr, uint32_t length) {
|
||||
void LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length) {
|
||||
printf("[OVERLORD] LoadISOFileToIOP %s, %d/%d bytes\n", file->name, length, file->size);
|
||||
IsoCommandLoadSingle cmd;
|
||||
cmd.cmd_id = LOAD_TO_IOP_CMD_ID;
|
||||
@@ -18,7 +18,7 @@ void LoadISOFileToIOP(FileRecord *file, void *addr, uint32_t length) {
|
||||
SendMbx(iso_mbx, &cmd);
|
||||
SleepThread();
|
||||
|
||||
if(cmd.status) {
|
||||
if (cmd.status) {
|
||||
cmd.length_to_copy = 0;
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ void LoadISOFileToIOP(FileRecord *file, void *addr, uint32_t length) {
|
||||
/*!
|
||||
* Load a File to IOP memory (blocking)
|
||||
*/
|
||||
void LoadISOFileToEE(FileRecord *file, uint32_t addr, uint32_t length) {
|
||||
void LoadISOFileToEE(FileRecord* file, uint32_t addr, uint32_t length) {
|
||||
printf("[OVERLORD] LoadISOFileToEE %s, %d/%d bytes\n", file->name, length, file->size);
|
||||
IsoCommandLoadSingle cmd;
|
||||
cmd.cmd_id = LOAD_TO_EE_CMD_ID;
|
||||
@@ -38,7 +38,7 @@ void LoadISOFileToEE(FileRecord *file, uint32_t addr, uint32_t length) {
|
||||
SendMbx(iso_mbx, &cmd);
|
||||
SleepThread();
|
||||
|
||||
if(cmd.status) {
|
||||
if (cmd.status) {
|
||||
cmd.length_to_copy = 0;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
#define JAK_V2_ISO_API_H
|
||||
#include "isocommon.h"
|
||||
|
||||
void LoadISOFileToIOP(FileRecord *file, void *addr, uint32_t length);
|
||||
void LoadISOFileToEE(FileRecord *file, uint32_t ee_addr, uint32_t length);
|
||||
void LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length);
|
||||
void LoadISOFileToEE(FileRecord* file, uint32_t ee_addr, uint32_t length);
|
||||
|
||||
#endif //JAK_V2_ISO_API_H
|
||||
#endif // JAK_V2_ISO_API_H
|
||||
|
||||
+74
-70
@@ -21,7 +21,6 @@ struct IsoStrBuffer {
|
||||
u8 data[STR_BUFFER_DATA_SIZE];
|
||||
};
|
||||
|
||||
|
||||
static IsoBuffer sBuffer[N_BUFFERS];
|
||||
static IsoStrBuffer sStrBuffer[N_STR_BUFFERS];
|
||||
static IsoBuffer* sFreeBuffer;
|
||||
@@ -36,7 +35,7 @@ VagCommand vag_cmds[N_VAG_CMDS];
|
||||
static s32 sSema;
|
||||
|
||||
IsoBufferHeader* TryAllocateBuffer(uint32_t size);
|
||||
void ReleaseMessage(IsoMessage *cmd);
|
||||
void ReleaseMessage(IsoMessage* cmd);
|
||||
void FreeVAGCommand(VagCommand* cmd);
|
||||
|
||||
void iso_queue_init_globals() {
|
||||
@@ -44,7 +43,8 @@ void iso_queue_init_globals() {
|
||||
memset(sStrBuffer, 0, sizeof(sStrBuffer));
|
||||
sFreeBuffer = nullptr;
|
||||
sFreeStrBuffer = nullptr;
|
||||
for(auto& e : gPriStack) e.reset();
|
||||
for (auto& e : gPriStack)
|
||||
e.reset();
|
||||
|
||||
vag_cmd_cnt = 0;
|
||||
vag_cmd_used = 0;
|
||||
@@ -54,25 +54,25 @@ void iso_queue_init_globals() {
|
||||
}
|
||||
|
||||
void PriStackEntry::reset() {
|
||||
for(auto& c : cmds) c = nullptr;
|
||||
for (auto& c : cmds)
|
||||
c = nullptr;
|
||||
n = 0;
|
||||
for(auto& x : names) x.clear();
|
||||
for (auto& x : names)
|
||||
x.clear();
|
||||
}
|
||||
|
||||
|
||||
void InitBuffers() {
|
||||
|
||||
// chain all buffers together and set them as free.
|
||||
for(uint32_t i = 0; i < N_BUFFERS; i++) {
|
||||
for (uint32_t i = 0; i < N_BUFFERS; i++) {
|
||||
sBuffer[i].header.data = nullptr;
|
||||
sBuffer[i].header.data_size = 0;
|
||||
sBuffer[i].header.buffer_size = BUFFER_PAGE_SIZE;
|
||||
sBuffer[i].header.next = &sBuffer[i+1].header;
|
||||
sBuffer[i].header.next = &sBuffer[i + 1].header;
|
||||
}
|
||||
sBuffer[N_BUFFERS - 1].header.next = nullptr;
|
||||
sFreeBuffer = &sBuffer[0];
|
||||
|
||||
for(uint32_t i = 0; i < N_STR_BUFFERS; i++) {
|
||||
for (uint32_t i = 0; i < N_STR_BUFFERS; i++) {
|
||||
sStrBuffer[i].header.data = nullptr;
|
||||
sStrBuffer[i].header.data_size = 0;
|
||||
sStrBuffer[i].header.buffer_size = STR_BUFFER_DATA_SIZE;
|
||||
@@ -89,19 +89,20 @@ void InitBuffers() {
|
||||
params.init_count = 0;
|
||||
sSema = CreateSema(¶ms);
|
||||
|
||||
if(sSema < 0) {
|
||||
for(;;) {
|
||||
if (sSema < 0) {
|
||||
for (;;) {
|
||||
printf("[OVERLORD] VAG Semaphore creation failed!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Allocate a buffer of the given size. If not possible, loop forever. Size must be BUFFER_PAGE_SIZE or STR_BUFFER_DATA_SIZE,
|
||||
* Allocate a buffer of the given size. If not possible, loop forever. Size must be BUFFER_PAGE_SIZE
|
||||
* or STR_BUFFER_DATA_SIZE,
|
||||
*/
|
||||
IsoBufferHeader* AllocateBuffer(uint32_t size) {
|
||||
IsoBufferHeader *buffer = TryAllocateBuffer(size);
|
||||
if(buffer) {
|
||||
IsoBufferHeader* buffer = TryAllocateBuffer(size);
|
||||
if (buffer) {
|
||||
printf("--------------- allocated buffer size %d\n", size);
|
||||
return buffer;
|
||||
} else {
|
||||
@@ -111,17 +112,16 @@ IsoBufferHeader* AllocateBuffer(uint32_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Allocate a buffer of given size. If the size isn't BUFFER_PAGE_SIZE, you get a streaming buffer (STR_BUFFER_DATA_SIZE).
|
||||
* If no allocation can be done, return nullptr.
|
||||
* Allocate a buffer of given size. If the size isn't BUFFER_PAGE_SIZE, you get a streaming buffer
|
||||
* (STR_BUFFER_DATA_SIZE). If no allocation can be done, return nullptr.
|
||||
*/
|
||||
IsoBufferHeader* TryAllocateBuffer(uint32_t size) {
|
||||
IsoStrBuffer* top_str = sFreeStrBuffer;
|
||||
IsoBuffer* top_buff = sFreeBuffer;
|
||||
|
||||
if(size == BUFFER_PAGE_SIZE) {
|
||||
if(sFreeBuffer) {
|
||||
if (size == BUFFER_PAGE_SIZE) {
|
||||
if (sFreeBuffer) {
|
||||
auto next = sFreeBuffer->header.next;
|
||||
sFreeBuffer->header.data = nullptr;
|
||||
sFreeBuffer = (IsoBuffer*)next;
|
||||
@@ -130,7 +130,7 @@ IsoBufferHeader* TryAllocateBuffer(uint32_t size) {
|
||||
return (IsoBufferHeader*)top_buff;
|
||||
}
|
||||
} else {
|
||||
if(sFreeStrBuffer) {
|
||||
if (sFreeStrBuffer) {
|
||||
auto next = sFreeStrBuffer->header.next;
|
||||
sFreeStrBuffer->header.data = nullptr;
|
||||
sFreeStrBuffer = (IsoStrBuffer*)next;
|
||||
@@ -146,10 +146,10 @@ IsoBufferHeader* TryAllocateBuffer(uint32_t size) {
|
||||
/*!
|
||||
* Return a buffer once you are done using it so somebody else can have a turn
|
||||
*/
|
||||
void FreeBuffer(IsoBufferHeader *buffer) {
|
||||
void FreeBuffer(IsoBufferHeader* buffer) {
|
||||
IsoBufferHeader* b = (IsoBufferHeader*)buffer;
|
||||
printf("--------------- free buffer size %d\n", b->buffer_size);
|
||||
if(b->buffer_size == BUFFER_PAGE_SIZE) {
|
||||
if (b->buffer_size == BUFFER_PAGE_SIZE) {
|
||||
b->next = sFreeBuffer;
|
||||
sFreeBuffer = (IsoBuffer*)b;
|
||||
} else {
|
||||
@@ -163,8 +163,8 @@ void FreeBuffer(IsoBufferHeader *buffer) {
|
||||
* The actual function does nothing.
|
||||
*/
|
||||
void DisplayQueue() {
|
||||
for(int pri = 0; pri < N_PRIORITIES; pri++) {
|
||||
for(int cmd = 0; cmd < (int)gPriStack[pri].n; cmd++) {
|
||||
for (int pri = 0; pri < N_PRIORITIES; pri++) {
|
||||
for (int cmd = 0; cmd < (int)gPriStack[pri].n; cmd++) {
|
||||
printf(" PRI %d elt %d %s\n", pri, cmd, gPriStack[pri].names[cmd].c_str());
|
||||
}
|
||||
}
|
||||
@@ -175,13 +175,14 @@ void DisplayQueue() {
|
||||
* If there is no room left in the queue, ReturnMessage with a CMD_STATUS_FAILED_TO_QUEUE.
|
||||
* Return 1 on success.
|
||||
*/
|
||||
u32 QueueMessage(IsoMessage *cmd, int32_t priority, const char *name) {
|
||||
u32 QueueMessage(IsoMessage* cmd, int32_t priority, const char* name) {
|
||||
u32 ok = gPriStack[priority].n != PRI_STACK_LENGTH;
|
||||
if(ok) {
|
||||
if (ok) {
|
||||
gPriStack[priority].cmds[gPriStack[priority].n] = cmd;
|
||||
gPriStack[priority].names[gPriStack[priority].n] = name;
|
||||
gPriStack[priority].n++;
|
||||
printf("[OVERLORD] Queue %d (%d/%d), %s\n", priority, gPriStack[priority].n, PRI_STACK_LENGTH, gPriStack[priority].names[gPriStack[priority].n - 1].c_str());
|
||||
printf("[OVERLORD] Queue %d (%d/%d), %s\n", priority, gPriStack[priority].n, PRI_STACK_LENGTH,
|
||||
gPriStack[priority].names[gPriStack[priority].n - 1].c_str());
|
||||
DisplayQueue();
|
||||
} else {
|
||||
printf("[OVERLORD ISO QUEUE] Failed to queue!\n");
|
||||
@@ -194,31 +195,31 @@ u32 QueueMessage(IsoMessage *cmd, int32_t priority, const char *name) {
|
||||
/*!
|
||||
* Remove a message from the priority stack.
|
||||
*/
|
||||
void UnqueueMessage(IsoMessage *cmd) {
|
||||
void UnqueueMessage(IsoMessage* cmd) {
|
||||
int pri = 0;
|
||||
u32 idx = 0;
|
||||
PriStackEntry* pse;
|
||||
|
||||
// loop over priorities
|
||||
for(pri = 0; pri < N_PRIORITIES; pri++) {
|
||||
for (pri = 0; pri < N_PRIORITIES; pri++) {
|
||||
pse = gPriStack + pri;
|
||||
|
||||
// loop over entries
|
||||
for(idx = 0; idx < gPriStack[pri].n; idx++) {
|
||||
if(pse->cmds[idx] == cmd) {
|
||||
for (idx = 0; idx < gPriStack[pri].n; idx++) {
|
||||
if (pse->cmds[idx] == cmd) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[OVERLORD ISO QUEUE] Failed to unqueue!\n");
|
||||
|
||||
found:
|
||||
found:
|
||||
assert(gPriStack[pri].cmds[idx] == cmd);
|
||||
|
||||
// pop
|
||||
gPriStack[pri].n--;
|
||||
// and move other entries up.
|
||||
while(idx < gPriStack[pri].n) {
|
||||
while (idx < gPriStack[pri].n) {
|
||||
pse->cmds[idx] = pse->cmds[idx + 1];
|
||||
idx++;
|
||||
}
|
||||
@@ -227,33 +228,32 @@ void UnqueueMessage(IsoMessage *cmd) {
|
||||
|
||||
/*!
|
||||
* Get the highest priority message with an open buffer.
|
||||
* (Note - messages with priority less than max priority will be gotten if they have < 2 buffers filled)
|
||||
* (Note - messages with priority less than max priority will be gotten if they have < 2 buffers
|
||||
* filled)
|
||||
* @return
|
||||
*/
|
||||
IsoMessage* GetMessage() {
|
||||
// loop over all priorities
|
||||
for(int pri = (N_PRIORITIES - 1); pri >= 0; pri--) {
|
||||
for (int pri = (N_PRIORITIES - 1); pri >= 0; pri--) {
|
||||
auto pse = gPriStack + pri;
|
||||
int idx = gPriStack[pri].n;
|
||||
for(idx = idx - 1; idx >= 0; idx--) {
|
||||
if(pse->cmds[idx]->fd &&
|
||||
pse->cmds[idx]->status == CMD_STATUS_IN_PROGRESS &&
|
||||
pse->cmds[idx]->ready_for_data) {
|
||||
if(pri == N_PRIORITIES - 1) {
|
||||
for (idx = idx - 1; idx >= 0; idx--) {
|
||||
if (pse->cmds[idx]->fd && pse->cmds[idx]->status == CMD_STATUS_IN_PROGRESS &&
|
||||
pse->cmds[idx]->ready_for_data) {
|
||||
if (pri == N_PRIORITIES - 1) {
|
||||
// return high priority commands only if they don't have any buffers filled
|
||||
if(!pse->cmds[idx]->callback_buffer) {
|
||||
if (!pse->cmds[idx]->callback_buffer) {
|
||||
return pse->cmds[idx];
|
||||
}
|
||||
} else {
|
||||
// return lower priority commands if they don't have 2 buffers filled.
|
||||
if(!pse->cmds[idx]->callback_buffer ||
|
||||
!(IsoBufferHeader*)(pse->cmds[idx]->callback_buffer)->next) {
|
||||
if (!pse->cmds[idx]->callback_buffer ||
|
||||
!(IsoBufferHeader*)(pse->cmds[idx]->callback_buffer)->next) {
|
||||
return pse->cmds[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -265,21 +265,27 @@ void ProcessMessageData() {
|
||||
int32_t pri = N_PRIORITIES - 1;
|
||||
|
||||
for (;;) {
|
||||
if (pri < 0) return;
|
||||
if (pri < 0)
|
||||
return;
|
||||
int32_t cmdID = gPriStack[pri].n;
|
||||
IsoMessage *popped_command;
|
||||
IsoMessage* popped_command;
|
||||
do {
|
||||
cmdID--;
|
||||
if (cmdID < 0) goto end_cur;
|
||||
if (cmdID < 0)
|
||||
goto end_cur;
|
||||
popped_command = gPriStack[pri].cmds[cmdID];
|
||||
auto* callback_buffer = popped_command->callback_buffer;
|
||||
if(popped_command->status == CMD_STATUS_IN_PROGRESS && callback_buffer) { // if we have a callback buffer (meaning a read finished and let us know)
|
||||
if (popped_command->status == CMD_STATUS_IN_PROGRESS &&
|
||||
callback_buffer) { // if we have a callback buffer (meaning a read finished and let us
|
||||
// know)
|
||||
// execute the callback!
|
||||
uint32_t callback_result = popped_command->callback_function(popped_command, callback_buffer);
|
||||
uint32_t callback_result =
|
||||
popped_command->callback_function(popped_command, callback_buffer);
|
||||
popped_command->status = callback_result;
|
||||
// printf("ProcessMessage Data set command %p status to %d\n", popped_command, popped_command->status);
|
||||
// printf("ProcessMessage Data set command %p status to %d\n", popped_command,
|
||||
// popped_command->status);
|
||||
// if we're done with the buffer, free it and load the next one (if there is one)
|
||||
if(callback_buffer->data_size == 0) {
|
||||
if (callback_buffer->data_size == 0) {
|
||||
popped_command->callback_buffer = (IsoBufferHeader*)callback_buffer->next;
|
||||
printf("free 1\n");
|
||||
FreeBuffer(callback_buffer);
|
||||
@@ -290,7 +296,7 @@ void ProcessMessageData() {
|
||||
ReturnMessage(popped_command);
|
||||
// return message todo this will free vag commands!
|
||||
pri++;
|
||||
end_cur:
|
||||
end_cur:
|
||||
pri--;
|
||||
}
|
||||
}
|
||||
@@ -298,9 +304,9 @@ void ProcessMessageData() {
|
||||
/*!
|
||||
* Wakeup thread/message mbx for a message
|
||||
*/
|
||||
void ReturnMessage(IsoMessage *cmd) {
|
||||
if(!cmd->messagebox_to_reply) {
|
||||
if(cmd->thread_id == 0) {
|
||||
void ReturnMessage(IsoMessage* cmd) {
|
||||
if (!cmd->messagebox_to_reply) {
|
||||
if (cmd->thread_id == 0) {
|
||||
FreeVAGCommand((VagCommand*)cmd);
|
||||
} else {
|
||||
WakeupThread(cmd->thread_id);
|
||||
@@ -313,17 +319,17 @@ void ReturnMessage(IsoMessage *cmd) {
|
||||
/*!
|
||||
* Free buffers, close files, and remove from priority stack
|
||||
*/
|
||||
void ReleaseMessage(IsoMessage *cmd) {
|
||||
void ReleaseMessage(IsoMessage* cmd) {
|
||||
// kill all buffers
|
||||
while(cmd->callback_buffer) {
|
||||
while (cmd->callback_buffer) {
|
||||
auto old_head = cmd->callback_buffer;
|
||||
cmd->callback_buffer = (IsoBufferHeader*)old_head->next;
|
||||
printf("free 2\n");
|
||||
printf("free 2\n");
|
||||
FreeBuffer(old_head);
|
||||
}
|
||||
|
||||
// close file
|
||||
if(cmd->fd) {
|
||||
if (cmd->fd) {
|
||||
isofs->close(cmd->fd);
|
||||
}
|
||||
|
||||
@@ -333,23 +339,22 @@ void ReleaseMessage(IsoMessage *cmd) {
|
||||
|
||||
// GetVAGCommand
|
||||
VagCommand* GetVAGCommand() {
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
// wait for command to be available
|
||||
while(vag_cmd_cnt == (N_VAG_CMDS - 1)) {
|
||||
while (vag_cmd_cnt == (N_VAG_CMDS - 1)) {
|
||||
DelayThread(100);
|
||||
}
|
||||
|
||||
// wait for VAG semaphore
|
||||
while(WaitSema(sSema)) {
|
||||
|
||||
while (WaitSema(sSema)) {
|
||||
}
|
||||
// try to get something.
|
||||
for(s32 i = 0; i < N_VAG_CMDS; i++) {
|
||||
if(!((vag_cmd_used >> (i & 0x1f)) & 1)) {
|
||||
for (s32 i = 0; i < N_VAG_CMDS; i++) {
|
||||
if (!((vag_cmd_used >> (i & 0x1f)) & 1)) {
|
||||
// free!
|
||||
vag_cmd_used |= (1 << (i & 0x1f));
|
||||
vag_cmd_cnt++;
|
||||
if(vag_cmd_cnt > max_vag_cmd_cnt) {
|
||||
if (vag_cmd_cnt > max_vag_cmd_cnt) {
|
||||
max_vag_cmd_cnt = vag_cmd_cnt;
|
||||
}
|
||||
SignalSema(sSema);
|
||||
@@ -363,9 +368,8 @@ VagCommand* GetVAGCommand() {
|
||||
|
||||
void FreeVAGCommand(VagCommand* cmd) {
|
||||
s32 idx = cmd - vag_cmds;
|
||||
if(idx >= 0 && idx < N_VAG_CMDS && ((vag_cmd_used >> (idx & 0x1f)) & 1)) {
|
||||
while(WaitSema(sSema)) {
|
||||
|
||||
if (idx >= 0 && idx < N_VAG_CMDS && ((vag_cmd_used >> (idx & 0x1f)) & 1)) {
|
||||
while (WaitSema(sSema)) {
|
||||
}
|
||||
|
||||
vag_cmd_used &= ~(1 << (idx & 0x1f));
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
#ifndef JAK_V2_ISO_QUEUE_H
|
||||
#define JAK_V2_ISO_QUEUE_H
|
||||
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "isocommon.h"
|
||||
|
||||
|
||||
|
||||
void iso_queue_init_globals();
|
||||
void InitBuffers();
|
||||
IsoBufferHeader* AllocateBuffer(uint32_t size);
|
||||
void FreeBuffer(IsoBufferHeader *buffer);
|
||||
u32 QueueMessage(IsoMessage *cmd, int32_t priority, const char *name);
|
||||
void UnqueueMessage(IsoMessage *cmd);
|
||||
void FreeBuffer(IsoBufferHeader* buffer);
|
||||
u32 QueueMessage(IsoMessage* cmd, int32_t priority, const char* name);
|
||||
void UnqueueMessage(IsoMessage* cmd);
|
||||
IsoMessage* GetMessage();
|
||||
void ProcessMessageData();
|
||||
void ReturnMessage(IsoMessage *cmd);
|
||||
void ReturnMessage(IsoMessage* cmd);
|
||||
|
||||
|
||||
#endif //JAK_V2_ISO_QUEUE_H
|
||||
#endif // JAK_V2_ISO_QUEUE_H
|
||||
|
||||
+26
-27
@@ -12,7 +12,7 @@ int start_overlord(int argc, const char* const* argv) {
|
||||
(void)argc;
|
||||
FlushDcache();
|
||||
CpuEnableIntr();
|
||||
if(!sceSifCheckInit()) {
|
||||
if (!sceSifCheckInit()) {
|
||||
sceSifInit();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ int start_overlord(int argc, const char* const* argv) {
|
||||
InitBanks();
|
||||
InitSound_Overlord();
|
||||
InitRamdisk();
|
||||
// RegisterVblankHandler(0, 0x20, VBlank_Handler, nullptr);
|
||||
// RegisterVblankHandler(0, 0x20, VBlank_Handler, nullptr);
|
||||
|
||||
ThreadParam thread_param;
|
||||
thread_param.attr = TH_C;
|
||||
@@ -28,37 +28,37 @@ int start_overlord(int argc, const char* const* argv) {
|
||||
thread_param.stackSize = 0x800;
|
||||
thread_param.option = 0;
|
||||
thread_param.entry = (void*)Thread_Server;
|
||||
strcpy(thread_param.name, "Server"); // added
|
||||
strcpy(thread_param.name, "Server"); // added
|
||||
auto thread_server = CreateThread(&thread_param);
|
||||
if(thread_server <= 0) {
|
||||
if (thread_server <= 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// thread_param.attr = TH_C;
|
||||
// thread_param.initPriority = 96;
|
||||
// thread_param.stackSize = 0x800;
|
||||
// thread_param.option = 0;
|
||||
// thread_param.entry = Thread_Player;
|
||||
// auto thread_player = CreateThread(&thread_param);
|
||||
// if(thread_player <= 0) {
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// thread_param.attr = TH_C;
|
||||
// thread_param.initPriority = 99;
|
||||
// thread_param.stackSize = 0x1000;
|
||||
// thread_param.option = 0;
|
||||
// thread_param.entry = Thread_Loader;
|
||||
// auto thread_loader = CreateThread(&thread_param);
|
||||
// if(thread_loader <= 0) {
|
||||
// return 1;
|
||||
// }
|
||||
// thread_param.attr = TH_C;
|
||||
// thread_param.initPriority = 96;
|
||||
// thread_param.stackSize = 0x800;
|
||||
// thread_param.option = 0;
|
||||
// thread_param.entry = Thread_Player;
|
||||
// auto thread_player = CreateThread(&thread_param);
|
||||
// if(thread_player <= 0) {
|
||||
// return 1;
|
||||
// }
|
||||
//
|
||||
// thread_param.attr = TH_C;
|
||||
// thread_param.initPriority = 99;
|
||||
// thread_param.stackSize = 0x1000;
|
||||
// thread_param.option = 0;
|
||||
// thread_param.entry = Thread_Loader;
|
||||
// auto thread_loader = CreateThread(&thread_param);
|
||||
// if(thread_loader <= 0) {
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
InitISOFS(argv[1], argv[2]);
|
||||
StartThread(thread_server, 0);
|
||||
|
||||
// StartThread(thread_player, 0);
|
||||
// StartThread(thread_loader, 0);
|
||||
// StartThread(thread_player, 0);
|
||||
// StartThread(thread_loader, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ int start_overlord(int argc, const char* const* argv) {
|
||||
* Loop endlessly and never return.
|
||||
*/
|
||||
void ExitIOP() {
|
||||
while(true) {
|
||||
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,4 @@
|
||||
int start_overlord(int argc, const char* const* argv);
|
||||
void ExitIOP();
|
||||
|
||||
#endif //JAK_V2_OVERLORD_H
|
||||
#endif // JAK_V2_OVERLORD_H
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "sbank.h"
|
||||
|
||||
void InitBanks() {
|
||||
|
||||
}
|
||||
void InitBanks() {}
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
void InitBanks();
|
||||
|
||||
#endif //JAK_V2_SBANK_H
|
||||
#endif // JAK_V2_SBANK_H
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <assert.h>
|
||||
#include "soundcommon.h"
|
||||
|
||||
|
||||
void PrintBankInfo(void* buffer) {
|
||||
(void)buffer;
|
||||
assert(false);
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
void PrintBankInfo(void* buffer);
|
||||
|
||||
#endif //JAK_V2_SOUNDCOMMON_H
|
||||
#endif // JAK_V2_SOUNDCOMMON_H
|
||||
|
||||
@@ -8,4 +8,4 @@ void srpc_init_globals();
|
||||
constexpr int MUSIC_TWEAK_SIZE = 0x204;
|
||||
extern u8 gMusicTweakInfo[MUSIC_TWEAK_SIZE];
|
||||
|
||||
#endif //JAK_V2_SRPC_H
|
||||
#endif // JAK_V2_SRPC_H
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "ssound.h"
|
||||
|
||||
void InitSound_Overlord() {
|
||||
|
||||
}
|
||||
void InitSound_Overlord() {}
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
void InitSound_Overlord();
|
||||
|
||||
#endif //JAK_V2_SSOUND_H
|
||||
#endif // JAK_V2_SSOUND_H
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
u32 STRThread();
|
||||
u32 PLAYThread();
|
||||
|
||||
#endif //JAK_V2_STREAM_H
|
||||
#endif // JAK_V2_STREAM_H
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
class Deci2Server;
|
||||
|
||||
|
||||
namespace ee {
|
||||
|
||||
void LIBRARY_INIT_sceDeci2();
|
||||
|
||||
+19
-17
@@ -31,22 +31,19 @@ void sceSifInitRpc(int mode) {
|
||||
* Flush Data Cache
|
||||
*/
|
||||
void FlushDcache() {
|
||||
// Do nothing! The data cache does not need to be flushed on x86 as we have no DMA which bypasses cache.
|
||||
// Do nothing! The data cache does not need to be flushed on x86 as we have no DMA which bypasses
|
||||
// cache.
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enable CPU Interrupts
|
||||
*/
|
||||
void CpuDisableIntr() {
|
||||
|
||||
}
|
||||
void CpuDisableIntr() {}
|
||||
|
||||
/*!
|
||||
* Disable CPU Interrupts
|
||||
*/
|
||||
void CpuEnableIntr() {
|
||||
|
||||
}
|
||||
void CpuEnableIntr() {}
|
||||
|
||||
namespace {
|
||||
::IOP* iop;
|
||||
@@ -68,15 +65,15 @@ void LIBRARY_kill() {
|
||||
* How much free memory is there, in bytes?
|
||||
*/
|
||||
int QueryTotalFreeMemSize() {
|
||||
// this value is somewhat arbitrary - it's a lot, but not enough to make OVERLORD think it is running on
|
||||
// an 8MB-of-IOP-RAM development machine.
|
||||
// this value is somewhat arbitrary - it's a lot, but not enough to make OVERLORD think it is
|
||||
// running on an 8MB-of-IOP-RAM development machine.
|
||||
return 0x100000;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Allocate memory.
|
||||
*/
|
||||
void *AllocSysMemory(int type, unsigned long size, void *addr) {
|
||||
* Allocate memory.
|
||||
*/
|
||||
void* AllocSysMemory(int type, unsigned long size, void* addr) {
|
||||
assert(type == SMEM_Low);
|
||||
assert(addr == nullptr);
|
||||
return iop->iop_alloc(size);
|
||||
@@ -112,8 +109,13 @@ void sceSifSetRpcQueue(sceSifQueueData* dq, int key) {
|
||||
iop->kernel.set_rpc_queue(dq, key);
|
||||
}
|
||||
|
||||
void sceSifRegisterRpc(sceSifServeData* serve, unsigned int request,
|
||||
sceSifRpcFunc func, void* buff, sceSifRpcFunc cfunc, void* cbuff, sceSifQueueData* qd) {
|
||||
void sceSifRegisterRpc(sceSifServeData* serve,
|
||||
unsigned int request,
|
||||
sceSifRpcFunc func,
|
||||
void* buff,
|
||||
sceSifRpcFunc cfunc,
|
||||
void* cbuff,
|
||||
sceSifQueueData* qd) {
|
||||
serve->command = request;
|
||||
serve->func = func;
|
||||
serve->buff = buff;
|
||||
@@ -140,11 +142,11 @@ int sceCdSync(int mode) {
|
||||
}
|
||||
|
||||
int sceCdGetError() {
|
||||
return 0; // no error
|
||||
return 0; // no error
|
||||
}
|
||||
|
||||
int sceCdGetDiskType() {
|
||||
return SCECdPS2DVD; // always a DVD (for now)
|
||||
return SCECdPS2DVD; // always a DVD (for now)
|
||||
}
|
||||
|
||||
int sceCdMmode(int media) {
|
||||
@@ -213,4 +215,4 @@ s32 WakeupThread(s32 thid) {
|
||||
iop->kernel.WakeupThread(thid);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace iop
|
||||
+29
-26
@@ -3,35 +3,34 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#define SMEM_Low (0)
|
||||
#define SMEM_Low (0)
|
||||
#define SMEM_High (1)
|
||||
#define SMEM_Addr (2)
|
||||
|
||||
#define SCECdCD 1
|
||||
#define SCECdDVD 2
|
||||
|
||||
#define SCECdIllgalMedia 0xff
|
||||
#define SCECdIllegalMedia 0xff
|
||||
#define SCECdDVDV 0xfe
|
||||
#define SCECdCDDA 0xfd
|
||||
#define SCECdPS2DVD 0x14
|
||||
#define SCECdPS2CD 0x12
|
||||
#define SCECdDETCT 0x01
|
||||
#define SCECdCD 1
|
||||
#define SCECdDVD 2
|
||||
|
||||
#define SCECdIllgalMedia 0xff
|
||||
#define SCECdIllegalMedia 0xff
|
||||
#define SCECdDVDV 0xfe
|
||||
#define SCECdCDDA 0xfd
|
||||
#define SCECdPS2DVD 0x14
|
||||
#define SCECdPS2CD 0x12
|
||||
#define SCECdDETCT 0x01
|
||||
|
||||
#define SCECdComplete 0x02
|
||||
#define SCECdNotReady 0x06
|
||||
#define KE_MBOX_NOMSG -424
|
||||
|
||||
#define TH_C 0x02000000
|
||||
#define TH_C 0x02000000
|
||||
|
||||
class IOP;
|
||||
|
||||
namespace iop {
|
||||
typedef void * (* sceSifRpcFunc)(unsigned int,void *,int);
|
||||
typedef void* (*sceSifRpcFunc)(unsigned int, void*, int);
|
||||
|
||||
struct sceSifServeData {
|
||||
unsigned int command; // the RPC ID
|
||||
unsigned int command; // the RPC ID
|
||||
sceSifRpcFunc func;
|
||||
void* buff;
|
||||
};
|
||||
@@ -48,14 +47,13 @@ struct sceCdRMode {
|
||||
uint8_t pad;
|
||||
};
|
||||
|
||||
struct sceSifDmaData{
|
||||
void* data;
|
||||
void* addr;
|
||||
unsigned int size;
|
||||
unsigned int mode;
|
||||
struct sceSifDmaData {
|
||||
void* data;
|
||||
void* addr;
|
||||
unsigned int size;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
|
||||
struct SysClock {
|
||||
uint32_t hi, lo;
|
||||
};
|
||||
@@ -72,7 +70,7 @@ struct MbxParam {
|
||||
struct ThreadParam {
|
||||
u32 attr;
|
||||
u32 option;
|
||||
void *entry;
|
||||
void* entry;
|
||||
int stackSize;
|
||||
int initPriority;
|
||||
|
||||
@@ -87,9 +85,9 @@ struct SemaParam {
|
||||
uint32_t option;
|
||||
};
|
||||
|
||||
//void PS2_RegisterIOP(IOP *iop);
|
||||
// void PS2_RegisterIOP(IOP *iop);
|
||||
int QueryTotalFreeMemSize();
|
||||
void *AllocSysMemory(int type, unsigned long size, void *addr);
|
||||
void* AllocSysMemory(int type, unsigned long size, void* addr);
|
||||
|
||||
int GetThreadId();
|
||||
void CpuDisableIntr();
|
||||
@@ -103,8 +101,13 @@ s32 WakeupThread(s32 thid);
|
||||
void sceSifInitRpc(int mode);
|
||||
void sceSifInitRpc(unsigned int mode);
|
||||
void sceSifSetRpcQueue(sceSifQueueData* dq, int key);
|
||||
void sceSifRegisterRpc(sceSifServeData* serve, unsigned int request,
|
||||
sceSifRpcFunc func, void* buff, sceSifRpcFunc cfunc, void* cbuff, sceSifQueueData* qd);
|
||||
void sceSifRegisterRpc(sceSifServeData* serve,
|
||||
unsigned int request,
|
||||
sceSifRpcFunc func,
|
||||
void* buff,
|
||||
sceSifRpcFunc cfunc,
|
||||
void* cbuff,
|
||||
sceSifQueueData* qd);
|
||||
void sceSifRpcLoop(sceSifQueueData* pd);
|
||||
|
||||
int sceCdRead(uint32_t logical_sector, uint32_t sectors, void* buf, sceCdRMode* mode);
|
||||
@@ -135,6 +138,6 @@ void sceSifInit();
|
||||
void LIBRARY_INIT();
|
||||
void LIBRARY_register(::IOP* i);
|
||||
void LIBRARY_kill();
|
||||
}
|
||||
} // namespace iop
|
||||
|
||||
#endif // JAK1_IOP_H
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace ee {
|
||||
namespace {
|
||||
// CD/DVD media type set by sceCdMMode
|
||||
int media_mode;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void LIBRARY_INIT_sceCd() {
|
||||
media_mode = -1;
|
||||
@@ -21,9 +21,9 @@ void LIBRARY_INIT_sceCd() {
|
||||
* Initialize the CD/DVD subsystem.
|
||||
* init_mode should be SCECdINIT
|
||||
*/
|
||||
int sceCdInit(int init_mode){
|
||||
int sceCdInit(int init_mode) {
|
||||
assert(init_mode == SCECdINIT);
|
||||
return 1; // Initialization was performed normally
|
||||
return 1; // Initialization was performed normally
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -31,7 +31,7 @@ int sceCdInit(int init_mode){
|
||||
*/
|
||||
int sceCdMmode(int media) {
|
||||
media_mode = media;
|
||||
return 1; // If successful, returns 1
|
||||
return 1; // If successful, returns 1
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -49,7 +49,7 @@ int sceCdDiskReady(int mode) {
|
||||
*/
|
||||
int sceCdGetDiskType() {
|
||||
// if we set CD or DVD, return the appropriate PS2 game disk type.
|
||||
switch(media_mode) {
|
||||
switch (media_mode) {
|
||||
case SCECdCD:
|
||||
return SCECdPS2CD;
|
||||
case SCECdDVD:
|
||||
|
||||
+1
-1
@@ -8,4 +8,4 @@ int sceScfGetAspect() {
|
||||
int sceScfGetLanguage() {
|
||||
return SCE_ENGLISH_LANGUAGE;
|
||||
}
|
||||
}
|
||||
} // namespace ee
|
||||
+1
-1
@@ -26,6 +26,6 @@ int sceScfGetAspect();
|
||||
* Return a SONY SCE_LANGUAGE value, which differs from GOAL.
|
||||
*/
|
||||
int sceScfGetLanguage();
|
||||
}
|
||||
} // namespace ee
|
||||
|
||||
#endif // JAK1_LIBSCF_H
|
||||
|
||||
+19
-12
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace ee {
|
||||
|
||||
namespace {
|
||||
namespace {
|
||||
::IOP* iop;
|
||||
}
|
||||
|
||||
@@ -30,17 +30,16 @@ int sceSifSyncIop() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void sceFsReset() {
|
||||
|
||||
}
|
||||
void sceFsReset() {}
|
||||
|
||||
int sceSifLoadModule(const char* name, int arg_size, const char* args) {
|
||||
if(!strcmp(name, "cdrom0:\\\\DRIVERS\\\\OVERLORD.IRX;1") || !strcmp(name, "host0:binee/overlord.irx")) {
|
||||
if (!strcmp(name, "cdrom0:\\\\DRIVERS\\\\OVERLORD.IRX;1") ||
|
||||
!strcmp(name, "host0:binee/overlord.irx")) {
|
||||
const char* src = args;
|
||||
char* dst = iop->overlord_arg_data;
|
||||
int cnt;
|
||||
iop->overlord_argv[0] = nullptr;
|
||||
for(cnt = 1; src - args < arg_size; cnt++) {
|
||||
for (cnt = 1; src - args < arg_size; cnt++) {
|
||||
auto len = strlen(src);
|
||||
memcpy(dst, src, len + 1);
|
||||
iop->overlord_argv[cnt] = dst;
|
||||
@@ -49,8 +48,8 @@ int sceSifLoadModule(const char* name, int arg_size, const char* args) {
|
||||
}
|
||||
iop->overlord_argc = cnt;
|
||||
|
||||
for(int i = 0; i < cnt; i++) {
|
||||
if(iop->overlord_argv[i])
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
if (iop->overlord_argv[i])
|
||||
printf("arg %d : %s\n", i, iop->overlord_argv[i]);
|
||||
}
|
||||
iop->set_ee_main_mem(g_ee_main_mem);
|
||||
@@ -65,10 +64,18 @@ int sceMcInit() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
s32 sceSifCallRpc(sceSifClientData* bd, u32 fno, u32 mode, void* send, s32 ssize, void* recv, s32 rsize, void* end_func, void* end_para) {
|
||||
s32 sceSifCallRpc(sceSifClientData* bd,
|
||||
u32 fno,
|
||||
u32 mode,
|
||||
void* send,
|
||||
s32 ssize,
|
||||
void* recv,
|
||||
s32 rsize,
|
||||
void* end_func,
|
||||
void* end_para) {
|
||||
assert(!end_func);
|
||||
assert(!end_para);
|
||||
assert(mode == 1); // async
|
||||
assert(mode == 1); // async
|
||||
iop->kernel.sif_rpc(bd->rpcd.id, fno, mode, send, ssize, recv, rsize);
|
||||
return 0;
|
||||
}
|
||||
@@ -79,9 +86,9 @@ s32 sceSifCheckStatRpc(sceSifRpcData* bd) {
|
||||
}
|
||||
|
||||
s32 sceSifBindRpc(sceSifClientData* bd, u32 request, u32 mode) {
|
||||
assert(mode == 1); // async
|
||||
assert(mode == 1); // async
|
||||
bd->rpcd.id = request;
|
||||
bd->serve = (sceSifServeData*)1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace ee
|
||||
+18
-11
@@ -16,17 +16,16 @@ struct sceSifServeData {
|
||||
};
|
||||
|
||||
struct sceSifClientData {
|
||||
sceSifRpcData rpcd;
|
||||
// unsigned int command;
|
||||
void *buff;
|
||||
void *gp;
|
||||
// sceSifEndFunc func;
|
||||
void *para;
|
||||
// struct _sif_serve_data *serve;
|
||||
sceSifServeData *serve;
|
||||
sceSifRpcData rpcd;
|
||||
// unsigned int command;
|
||||
void* buff;
|
||||
void* gp;
|
||||
// sceSifEndFunc func;
|
||||
void* para;
|
||||
// struct _sif_serve_data *serve;
|
||||
sceSifServeData* serve;
|
||||
};
|
||||
|
||||
|
||||
void LIBRARY_sceSif_register(::IOP* i);
|
||||
void LIBRARY_INIT_sceSif();
|
||||
|
||||
@@ -36,9 +35,17 @@ int sceSifSyncIop();
|
||||
void sceFsReset();
|
||||
int sceSifLoadModule(const char* name, int arg_size, const char* args);
|
||||
int sceMcInit();
|
||||
s32 sceSifCallRpc(sceSifClientData* bd, u32 fno, u32 mode, void* send, s32 ssize, void* recv, s32 rsize, void* end_func, void* end_para);
|
||||
s32 sceSifCallRpc(sceSifClientData* bd,
|
||||
u32 fno,
|
||||
u32 mode,
|
||||
void* send,
|
||||
s32 ssize,
|
||||
void* recv,
|
||||
s32 rsize,
|
||||
void* end_func,
|
||||
void* end_para);
|
||||
s32 sceSifCheckStatRpc(sceSifRpcData* bd);
|
||||
s32 sceSifBindRpc(sceSifClientData* bd, u32 request, u32 mode);
|
||||
|
||||
}
|
||||
} // namespace ee
|
||||
#endif // JAK1_SIF_EE_H
|
||||
|
||||
+5
-5
@@ -3,7 +3,7 @@
|
||||
#include "stubs.h"
|
||||
|
||||
namespace ee {
|
||||
s32 sceOpen(const char *filename, s32 flag) {
|
||||
s32 sceOpen(const char* filename, s32 flag) {
|
||||
(void)filename;
|
||||
(void)flag;
|
||||
throw std::runtime_error("sceOpen NYI");
|
||||
@@ -14,14 +14,14 @@ s32 sceClose(s32 fd) {
|
||||
throw std::runtime_error("sceClose NYI");
|
||||
}
|
||||
|
||||
s32 sceRead(s32 fd, void *buf, s32 nbyte) {
|
||||
s32 sceRead(s32 fd, void* buf, s32 nbyte) {
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)nbyte;
|
||||
throw std::runtime_error("sceRead NYI");
|
||||
}
|
||||
|
||||
s32 sceWrite(s32 fd, const void *buf, s32 nbyte) {
|
||||
s32 sceWrite(s32 fd, const void* buf, s32 nbyte) {
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)nbyte;
|
||||
@@ -79,7 +79,7 @@ void FlushCache() {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace ee
|
||||
|
||||
namespace iop {
|
||||
u32 snd_BankLoadByLoc(u32 sector, u32 unk) {
|
||||
@@ -98,4 +98,4 @@ void snd_ResolveBankXREFS() {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace iop
|
||||
|
||||
+18
-19
@@ -4,33 +4,33 @@
|
||||
#include "common/common_types.h"
|
||||
|
||||
#ifndef SCE_SEEK_SET
|
||||
#define SCE_SEEK_SET (0)
|
||||
#define SCE_SEEK_SET (0)
|
||||
#endif
|
||||
#ifndef SCE_SEEK_CUR
|
||||
#define SCE_SEEK_CUR (1)
|
||||
#define SCE_SEEK_CUR (1)
|
||||
#endif
|
||||
#ifndef SCE_SEEK_END
|
||||
#define SCE_SEEK_END (2)
|
||||
#define SCE_SEEK_END (2)
|
||||
#endif
|
||||
|
||||
#define SCE_RDONLY 0x0001
|
||||
#define SCE_WRONLY 0x0002
|
||||
#define SCE_RDWR 0x0003
|
||||
#define SCE_NBLOCK 0x0010
|
||||
#define SCE_APPEND 0x0100
|
||||
#define SCE_CREAT 0x0200
|
||||
#define SCE_TRUNC 0x0400
|
||||
#define SCE_EXCL 0x0800
|
||||
#define SCE_NOBUF 0x4000
|
||||
#define SCE_NOWAIT 0x8000
|
||||
#define SCE_RDONLY 0x0001
|
||||
#define SCE_WRONLY 0x0002
|
||||
#define SCE_RDWR 0x0003
|
||||
#define SCE_NBLOCK 0x0010
|
||||
#define SCE_APPEND 0x0100
|
||||
#define SCE_CREAT 0x0200
|
||||
#define SCE_TRUNC 0x0400
|
||||
#define SCE_EXCL 0x0800
|
||||
#define SCE_NOBUF 0x4000
|
||||
#define SCE_NOWAIT 0x8000
|
||||
|
||||
#define SCE_PAD_DMA_BUFFER_SIZE 0x100
|
||||
|
||||
namespace ee {
|
||||
s32 sceOpen(const char *filename, s32 flag);
|
||||
s32 sceOpen(const char* filename, s32 flag);
|
||||
s32 sceClose(s32 fd);
|
||||
s32 sceRead(s32 fd, void *buf, s32 nbyte);
|
||||
s32 sceWrite(s32 fd, const void *buf, s32 nbyte);
|
||||
s32 sceRead(s32 fd, void* buf, s32 nbyte);
|
||||
s32 sceWrite(s32 fd, const void* buf, s32 nbyte);
|
||||
s32 sceLseek(s32 fd, s32 offset, s32 where);
|
||||
void sceGsSyncV();
|
||||
void sceGsSyncPath();
|
||||
@@ -42,13 +42,12 @@ void sceGsGetIMR();
|
||||
void sceGsExecStoreImage();
|
||||
void FlushCache();
|
||||
int scePadPortOpen(int port, int slot, void* data);
|
||||
}
|
||||
} // namespace ee
|
||||
|
||||
namespace iop {
|
||||
u32 snd_BankLoadByLoc(u32 sector, u32 unk);
|
||||
u32 snd_GetLastLoadError();
|
||||
void snd_ResolveBankXREFS();
|
||||
}
|
||||
|
||||
} // namespace iop
|
||||
|
||||
#endif // JAK1_STUBS_H
|
||||
|
||||
@@ -30,7 +30,6 @@ class Deci2Server {
|
||||
|
||||
void run();
|
||||
|
||||
|
||||
private:
|
||||
void accept_thread_func();
|
||||
bool kill_accept_thread = false;
|
||||
@@ -51,6 +50,4 @@ class Deci2Server {
|
||||
int* d2_driver_count = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // JAK1_DECI2SERVER_H
|
||||
|
||||
+59
-50
@@ -7,16 +7,18 @@
|
||||
* Create a new thread. Will not run the thread.
|
||||
*/
|
||||
s32 IOP_Kernel::CreateThread(std::string name, u32 (*func)()) {
|
||||
if(_currentThread != -1) throw std::runtime_error("tried to create thread from thread");
|
||||
if (_currentThread != -1)
|
||||
throw std::runtime_error("tried to create thread from thread");
|
||||
u32 ID = (u32)_nextThID++;
|
||||
if(threads.size() != ID) throw std::runtime_error("thread number error?");
|
||||
if (threads.size() != ID)
|
||||
throw std::runtime_error("thread number error?");
|
||||
// add entry
|
||||
threads.emplace_back(name, func, ID, this);
|
||||
// setup the thread!
|
||||
// printf("[IOP Kernel] SetupThread %s...\n", name.c_str());
|
||||
|
||||
// hack to allow creating a "null thread" which doesn't/can't run but occupies slot 0.
|
||||
if(func) {
|
||||
if (func) {
|
||||
_currentThread = ID;
|
||||
// create OS thread, will run the setupThread function
|
||||
threads.back().thread = new std::thread(&IOP_Kernel::setupThread, this, ID);
|
||||
@@ -26,7 +28,6 @@ s32 IOP_Kernel::CreateThread(std::string name, u32 (*func)()) {
|
||||
_currentThread = -1;
|
||||
}
|
||||
|
||||
|
||||
return ID;
|
||||
}
|
||||
|
||||
@@ -34,8 +35,8 @@ s32 IOP_Kernel::CreateThread(std::string name, u32 (*func)()) {
|
||||
* Start a thread. Runs it once, then marks it to run on each dispatch of the IOP kernel.
|
||||
*/
|
||||
void IOP_Kernel::StartThread(s32 id) {
|
||||
threads.at(id).started = true; // mark for run
|
||||
runThread(id); // run now
|
||||
threads.at(id).started = true; // mark for run
|
||||
runThread(id); // run now
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -46,7 +47,7 @@ void IOP_Kernel::setupThread(s32 id) {
|
||||
returnToKernel();
|
||||
threads.at(id).waitForDispatch();
|
||||
// printf("[IOP Kernel] Thread %s first dispatch!\n", threads.at(id).name.c_str());
|
||||
if(_currentThread != id) {
|
||||
if (_currentThread != id) {
|
||||
throw std::runtime_error("the wrong thread has run!\n");
|
||||
}
|
||||
(threads.at(id).function)();
|
||||
@@ -59,7 +60,8 @@ void IOP_Kernel::setupThread(s32 id) {
|
||||
* Run a thread (call from kernel)
|
||||
*/
|
||||
void IOP_Kernel::runThread(s32 id) {
|
||||
if(_currentThread != -1) throw std::runtime_error("tried to runThread in a thread");
|
||||
if (_currentThread != -1)
|
||||
throw std::runtime_error("tried to runThread in a thread");
|
||||
_currentThread = id;
|
||||
threads.at(id).dispatch();
|
||||
threads.at(id).waitForReturnToKernel();
|
||||
@@ -75,7 +77,7 @@ void IOP_Kernel::SuspendThread() {
|
||||
s32 oldThread = getCurrentThread();
|
||||
threads.at(oldThread).returnToKernel();
|
||||
threads.at(oldThread).waitForDispatch();
|
||||
if(_currentThread != oldThread) {
|
||||
if (_currentThread != oldThread) {
|
||||
throw std::runtime_error("bad resume");
|
||||
}
|
||||
}
|
||||
@@ -84,9 +86,9 @@ void IOP_Kernel::SuspendThread() {
|
||||
* Sleep a thread. Must be explicitly woken up.
|
||||
*/
|
||||
void IOP_Kernel::SleepThread() {
|
||||
if(getCurrentThread() == -1) {
|
||||
if (getCurrentThread() == -1) {
|
||||
mainThreadSleep = true;
|
||||
while(mainThreadSleep) {
|
||||
while (mainThreadSleep) {
|
||||
dispatchAll();
|
||||
}
|
||||
} else {
|
||||
@@ -99,7 +101,7 @@ void IOP_Kernel::SleepThread() {
|
||||
* Wake up a thread. Doesn't run it immediately though.
|
||||
*/
|
||||
void IOP_Kernel::WakeupThread(s32 id) {
|
||||
if(id == -1) {
|
||||
if (id == -1) {
|
||||
mainThreadSleep = false;
|
||||
} else {
|
||||
threads.at(id).started = true;
|
||||
@@ -111,14 +113,14 @@ void IOP_Kernel::WakeupThread(s32 id) {
|
||||
* Dispatch all IOP threads.
|
||||
*/
|
||||
void IOP_Kernel::dispatchAll() {
|
||||
for(u64 i = 0; i < threads.size(); i++) {
|
||||
if(threads[i].started && !threads[i].done) {
|
||||
// printf("[IOP Kernel] Dispatch %s (%ld)\n", threads[i].name.c_str(), i);
|
||||
for (u64 i = 0; i < threads.size(); i++) {
|
||||
if (threads[i].started && !threads[i].done) {
|
||||
// printf("[IOP Kernel] Dispatch %s (%ld)\n", threads[i].name.c_str(), i);
|
||||
_currentThread = i;
|
||||
threads[i].dispatch();
|
||||
threads[i].waitForReturnToKernel();
|
||||
_currentThread = -1;
|
||||
//printf("[IOP Kernel] back to kernel!\n");
|
||||
// printf("[IOP Kernel] back to kernel!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +130,8 @@ void IOP_Kernel::dispatchAll() {
|
||||
*/
|
||||
void IopThreadRecord::returnToKernel() {
|
||||
runThreadReady = false;
|
||||
if(kernel->getCurrentThread() != thID) throw std::runtime_error("tried to sleep the wrong thread!");
|
||||
if (kernel->getCurrentThread() != thID)
|
||||
throw std::runtime_error("tried to sleep the wrong thread!");
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(*threadToKernelMutex);
|
||||
@@ -142,7 +145,8 @@ void IopThreadRecord::returnToKernel() {
|
||||
*/
|
||||
void IopThreadRecord::dispatch() {
|
||||
syscallReady = false;
|
||||
if(kernel->getCurrentThread() != thID) throw std::runtime_error("tried to dispatch the wrong thread!");
|
||||
if (kernel->getCurrentThread() != thID)
|
||||
throw std::runtime_error("tried to dispatch the wrong thread!");
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(*kernelToThreadMutex);
|
||||
runThreadReady = true;
|
||||
@@ -155,22 +159,22 @@ void IopThreadRecord::dispatch() {
|
||||
*/
|
||||
void IopThreadRecord::waitForReturnToKernel() {
|
||||
std::unique_lock<std::mutex> lck(*threadToKernelMutex);
|
||||
threadToKernelCV->wait(lck, [this]{return syscallReady;});
|
||||
// syscallReady = false;
|
||||
threadToKernelCV->wait(lck, [this] { return syscallReady; });
|
||||
// syscallReady = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Thread waits for kernel to dispatch it.
|
||||
*/
|
||||
void IopThreadRecord::waitForDispatch() {
|
||||
//if(kernel->getCurrentThread() == -1) throw std::runtime_error("tried to suspend main!\n");
|
||||
// if(kernel->getCurrentThread() == -1) throw std::runtime_error("tried to suspend main!\n");
|
||||
std::unique_lock<std::mutex> lck(*kernelToThreadMutex);
|
||||
kernelToThreadCV->wait(lck, [this]{return runThreadReady;});
|
||||
//runThreadReady = false;
|
||||
kernelToThreadCV->wait(lck, [this] { return runThreadReady; });
|
||||
// runThreadReady = false;
|
||||
}
|
||||
|
||||
void IOP_Kernel::set_rpc_queue(iop::sceSifQueueData *qd, u32 thread) {
|
||||
for(const auto& r : sif_records) {
|
||||
void IOP_Kernel::set_rpc_queue(iop::sceSifQueueData* qd, u32 thread) {
|
||||
for (const auto& r : sif_records) {
|
||||
assert(!(r.qd == qd || r.thread_to_wake == thread));
|
||||
}
|
||||
SifRecord rec;
|
||||
@@ -179,14 +183,14 @@ void IOP_Kernel::set_rpc_queue(iop::sceSifQueueData *qd, u32 thread) {
|
||||
sif_records.push_back(rec);
|
||||
}
|
||||
|
||||
typedef void * (* sif_rpc_handler)(unsigned int,void *,int);
|
||||
typedef void* (*sif_rpc_handler)(unsigned int, void*, int);
|
||||
|
||||
bool IOP_Kernel::sif_busy(u32 id) {
|
||||
sif_mtx.lock();
|
||||
bool rv = false;
|
||||
bool found = false;
|
||||
for(auto& r : sif_records) {
|
||||
if(r.qd->serve_data->command == id) {
|
||||
for (auto& r : sif_records) {
|
||||
if (r.qd->serve_data->command == id) {
|
||||
rv = !r.cmd.finished;
|
||||
found = true;
|
||||
break;
|
||||
@@ -197,14 +201,19 @@ bool IOP_Kernel::sif_busy(u32 id) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
void IOP_Kernel::sif_rpc(s32 rpcChannel, u32 fno, bool async, void *sendBuff, s32 sendSize, void *recvBuff,
|
||||
void IOP_Kernel::sif_rpc(s32 rpcChannel,
|
||||
u32 fno,
|
||||
bool async,
|
||||
void* sendBuff,
|
||||
s32 sendSize,
|
||||
void* recvBuff,
|
||||
s32 recvSize) {
|
||||
assert(async);
|
||||
sif_mtx.lock();
|
||||
// step 1 - find entry
|
||||
SifRecord* rec = nullptr;
|
||||
for(auto& e : sif_records) {
|
||||
if(e.qd->serve_data->command == (u32)rpcChannel) {
|
||||
for (auto& e : sif_records) {
|
||||
if (e.qd->serve_data->command == (u32)rpcChannel) {
|
||||
rec = &e;
|
||||
}
|
||||
}
|
||||
@@ -229,15 +238,15 @@ void IOP_Kernel::sif_rpc(s32 rpcChannel, u32 fno, bool async, void *sendBuff, s3
|
||||
}
|
||||
|
||||
void IOP_Kernel::rpc_loop(iop::sceSifQueueData* qd) {
|
||||
while(true) {
|
||||
while (true) {
|
||||
bool got_cmd = false;
|
||||
SifRpcCommand cmd;
|
||||
sif_rpc_handler func = nullptr;
|
||||
|
||||
// get command and mark it as started if we get it
|
||||
sif_mtx.lock();
|
||||
for(auto& r : sif_records) {
|
||||
if(r.qd == qd) {
|
||||
for (auto& r : sif_records) {
|
||||
if (r.qd == qd) {
|
||||
cmd = r.cmd;
|
||||
got_cmd = true;
|
||||
r.cmd.started = true;
|
||||
@@ -247,41 +256,40 @@ void IOP_Kernel::rpc_loop(iop::sceSifQueueData* qd) {
|
||||
sif_mtx.unlock();
|
||||
|
||||
// handle command
|
||||
if(got_cmd) {
|
||||
if(cmd.shutdown_now) {
|
||||
if (got_cmd) {
|
||||
if (cmd.shutdown_now) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!cmd.started) {
|
||||
if (!cmd.started) {
|
||||
// cf
|
||||
assert(func);
|
||||
auto data = func(cmd.fno, cmd.buff, cmd.size);
|
||||
if(cmd.copy_back_buff && cmd.copy_back_size) {
|
||||
if (cmd.copy_back_buff && cmd.copy_back_size) {
|
||||
memcpy(cmd.copy_back_buff, data, cmd.copy_back_size);
|
||||
}
|
||||
|
||||
sif_mtx.lock();
|
||||
for(auto& r : sif_records) {
|
||||
if(r.qd == qd) {
|
||||
for (auto& r : sif_records) {
|
||||
if (r.qd == qd) {
|
||||
assert(r.cmd.started);
|
||||
r.cmd.finished = true;
|
||||
}
|
||||
}
|
||||
sif_mtx.unlock();
|
||||
|
||||
}
|
||||
}
|
||||
SuspendThread();
|
||||
}
|
||||
}
|
||||
|
||||
void IOP_Kernel::read_disc_sectors(u32 sector, u32 sectors, void *buffer) {
|
||||
if(!iso_disc_file) {
|
||||
void IOP_Kernel::read_disc_sectors(u32 sector, u32 sectors, void* buffer) {
|
||||
if (!iso_disc_file) {
|
||||
iso_disc_file = fopen("./disc.iso", "rb");
|
||||
}
|
||||
|
||||
assert(iso_disc_file);
|
||||
if(fseek(iso_disc_file, sector * 0x800, SEEK_SET)) {
|
||||
if (fseek(iso_disc_file, sector * 0x800, SEEK_SET)) {
|
||||
assert(false);
|
||||
}
|
||||
auto rv = fread(buffer, sectors * 0x800, 1, iso_disc_file);
|
||||
@@ -290,17 +298,18 @@ void IOP_Kernel::read_disc_sectors(u32 sector, u32 sectors, void *buffer) {
|
||||
|
||||
void IOP_Kernel::shutdown() {
|
||||
// shutdown most threads
|
||||
for(auto& r : sif_records) {
|
||||
for (auto& r : sif_records) {
|
||||
r.cmd.shutdown_now = true;
|
||||
}
|
||||
|
||||
for(auto& t : threads) {
|
||||
for (auto& t : threads) {
|
||||
t.wantExit = true;
|
||||
}
|
||||
|
||||
for(auto& t : threads) {
|
||||
if(t.thID == 0) continue;
|
||||
while(!t.done) {
|
||||
for (auto& t : threads) {
|
||||
if (t.thID == 0)
|
||||
continue;
|
||||
while (!t.done) {
|
||||
dispatchAll();
|
||||
}
|
||||
t.thread->join();
|
||||
@@ -308,7 +317,7 @@ void IOP_Kernel::shutdown() {
|
||||
}
|
||||
|
||||
IOP_Kernel::~IOP_Kernel() {
|
||||
if(iso_disc_file) {
|
||||
if (iso_disc_file) {
|
||||
fclose(iso_disc_file);
|
||||
}
|
||||
}
|
||||
+30
-30
@@ -12,7 +12,7 @@
|
||||
|
||||
class IOP_Kernel;
|
||||
namespace iop {
|
||||
struct sceSifQueueData;
|
||||
struct sceSifQueueData;
|
||||
}
|
||||
|
||||
struct SifRpcCommand {
|
||||
@@ -28,7 +28,6 @@ struct SifRpcCommand {
|
||||
int copy_back_size;
|
||||
};
|
||||
|
||||
|
||||
struct SifRecord {
|
||||
iop::sceSifQueueData* qd;
|
||||
SifRpcCommand cmd;
|
||||
@@ -36,14 +35,14 @@ struct SifRecord {
|
||||
};
|
||||
|
||||
struct IopThreadRecord {
|
||||
IopThreadRecord(std::string n, u32 (*f)(), s32 ID, IOP_Kernel* k) : name(n), function(f), thID(ID), kernel(k) {
|
||||
IopThreadRecord(std::string n, u32 (*f)(), s32 ID, IOP_Kernel* k)
|
||||
: name(n), function(f), thID(ID), kernel(k) {
|
||||
kernelToThreadCV = new std::condition_variable;
|
||||
threadToKernelCV = new std::condition_variable;
|
||||
kernelToThreadMutex = new std::mutex;
|
||||
threadToKernelMutex = new std::mutex;
|
||||
}
|
||||
|
||||
|
||||
~IopThreadRecord() {
|
||||
delete kernelToThreadCV;
|
||||
delete threadToKernelCV;
|
||||
@@ -72,9 +71,8 @@ struct IopThreadRecord {
|
||||
void dispatch();
|
||||
};
|
||||
|
||||
|
||||
class IOP_Kernel {
|
||||
public:
|
||||
public:
|
||||
IOP_Kernel() {
|
||||
// this ugly hack
|
||||
threads.reserve(16);
|
||||
@@ -90,7 +88,7 @@ public:
|
||||
void SleepThread();
|
||||
void WakeupThread(s32 id);
|
||||
void dispatchAll();
|
||||
void set_rpc_queue(iop::sceSifQueueData *qd, u32 thread);
|
||||
void set_rpc_queue(iop::sceSifQueueData* qd, u32 thread);
|
||||
void rpc_loop(iop::sceSifQueueData* qd);
|
||||
void shutdown();
|
||||
|
||||
@@ -98,17 +96,15 @@ public:
|
||||
* Resume the kernel.
|
||||
*/
|
||||
void returnToKernel() {
|
||||
if(_currentThread < 0) throw std::runtime_error("tried to return to kernel not in a thread");
|
||||
if (_currentThread < 0)
|
||||
throw std::runtime_error("tried to return to kernel not in a thread");
|
||||
threads[_currentThread].returnToKernel();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Get current thread ID.
|
||||
*/
|
||||
s32 getCurrentThread() {
|
||||
return _currentThread;
|
||||
}
|
||||
|
||||
s32 getCurrentThread() { return _currentThread; }
|
||||
|
||||
/*!
|
||||
* Create a message box
|
||||
@@ -124,17 +120,18 @@ public:
|
||||
* Returns if it got something.
|
||||
*/
|
||||
s32 PollMbx(void** msg, s32 mbx) {
|
||||
if(_currentThread != -1 && threads.at(_currentThread).wantExit) {
|
||||
if (_currentThread != -1 && threads.at(_currentThread).wantExit) {
|
||||
// total hack - returning this value causes the ISO thread to error out and quit.
|
||||
return -0x1a9;
|
||||
}
|
||||
// printf("poll %d %ld\n", mbx, mbxs.size());
|
||||
if(mbx >= (s32) mbxs.size()) throw std::runtime_error("invalid PollMbx");
|
||||
s32 gotSomething = mbxs[mbx].empty() ? 0 : 1;
|
||||
if(gotSomething) {
|
||||
// printf("poll %d %ld\n", mbx, mbxs.size());
|
||||
if (mbx >= (s32)mbxs.size())
|
||||
throw std::runtime_error("invalid PollMbx");
|
||||
s32 gotSomething = mbxs[mbx].empty() ? 0 : 1;
|
||||
if (gotSomething) {
|
||||
void* thing = mbxs[mbx].front();
|
||||
// printf("pop from msgbox %d %p\n", mbx, thing);
|
||||
if(msg)
|
||||
// printf("pop from msgbox %d %p\n", mbx, thing);
|
||||
if (msg)
|
||||
*msg = thing;
|
||||
mbxs[mbx].pop();
|
||||
}
|
||||
@@ -146,24 +143,28 @@ public:
|
||||
* Push something into a mbx
|
||||
*/
|
||||
s32 SendMbx(s32 mbx, void* value) {
|
||||
if(mbx >= (s32) mbxs.size()) throw std::runtime_error("invalid SendMbx");
|
||||
if (mbx >= (s32)mbxs.size())
|
||||
throw std::runtime_error("invalid SendMbx");
|
||||
mbxs[mbx].push(value);
|
||||
// printf("push into messagebox %d %p\n", mbx, value);
|
||||
// printf("mbx size %ld\n", mbxs.size());
|
||||
// printf("push into messagebox %d %p\n", mbx, value);
|
||||
// printf("mbx size %ld\n", mbxs.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 CreateSema() {
|
||||
return 1;
|
||||
}
|
||||
s32 CreateSema() { return 1; }
|
||||
|
||||
void read_disc_sectors(u32 sector, u32 sectors, void* buffer);
|
||||
bool sif_busy(u32 id);
|
||||
|
||||
void sif_rpc(s32 rpcChannel, u32 fno, bool async, void *sendBuff, s32 sendSize, void *recvBuff, s32 recvSize);
|
||||
void sif_rpc(s32 rpcChannel,
|
||||
u32 fno,
|
||||
bool async,
|
||||
void* sendBuff,
|
||||
s32 sendSize,
|
||||
void* recvBuff,
|
||||
s32 recvSize);
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
void setupThread(s32 id);
|
||||
void runThread(s32 id);
|
||||
s32 _nextThID = 0;
|
||||
@@ -176,5 +177,4 @@ private:
|
||||
std::mutex sif_mtx;
|
||||
};
|
||||
|
||||
|
||||
#endif //JAK_IOP_KERNEL_H
|
||||
#endif // JAK_IOP_KERNEL_H
|
||||
|
||||
+11
-12
@@ -14,7 +14,6 @@
|
||||
#include <condition_variable>
|
||||
#include "Timer.h"
|
||||
|
||||
|
||||
constexpr int MAX_SYSTEM_THREADS = 16;
|
||||
|
||||
class SystemThreadInterface;
|
||||
@@ -28,13 +27,13 @@ class SystemThreadManager;
|
||||
* statistics.
|
||||
*/
|
||||
class SystemThread {
|
||||
public:
|
||||
public:
|
||||
void start(std::function<void(SystemThreadInterface&)> f);
|
||||
void join();
|
||||
void stop();
|
||||
SystemThread() = default;
|
||||
|
||||
private:
|
||||
private:
|
||||
friend class SystemThreadInterface;
|
||||
friend class SystemThreadManager;
|
||||
friend void* bootstrap_thread_func(void* thd);
|
||||
@@ -42,7 +41,7 @@ private:
|
||||
std::string name = "invalid";
|
||||
pthread_t thread;
|
||||
SystemThreadManager* manager;
|
||||
std::function<void(SystemThreadInterface &)> function;
|
||||
std::function<void(SystemThreadInterface&)> function;
|
||||
bool initialization_complete = false;
|
||||
std::mutex initialization_mutex;
|
||||
std::condition_variable initialization_cv;
|
||||
@@ -60,15 +59,14 @@ private:
|
||||
* The interface used by a thread in the runtime.
|
||||
*/
|
||||
class SystemThreadInterface {
|
||||
public:
|
||||
SystemThreadInterface(SystemThread* p) : thread(*p) {
|
||||
|
||||
}
|
||||
public:
|
||||
SystemThreadInterface(SystemThread* p) : thread(*p) {}
|
||||
void initialization_complete();
|
||||
void report_perf_stats();
|
||||
bool get_want_exit() const;
|
||||
void trigger_shutdown();
|
||||
private:
|
||||
|
||||
private:
|
||||
SystemThread& thread;
|
||||
};
|
||||
|
||||
@@ -76,14 +74,15 @@ private:
|
||||
* A manager of all threads in the runtime.
|
||||
*/
|
||||
class SystemThreadManager {
|
||||
public:
|
||||
public:
|
||||
SystemThread& create_thread(const std::string& name);
|
||||
void print_stats();
|
||||
void shutdown();
|
||||
void join();
|
||||
private:
|
||||
|
||||
private:
|
||||
std::array<SystemThread, MAX_SYSTEM_THREADS> threads;
|
||||
int thread_count = 0;
|
||||
};
|
||||
|
||||
#endif //RUNTIME_SYSTEMTHREAD_H
|
||||
#endif // RUNTIME_SYSTEMTHREAD_H
|
||||
|
||||
+8
-17
@@ -6,32 +6,23 @@
|
||||
#include <cstdint>
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
explicit Timer() {
|
||||
start();
|
||||
}
|
||||
public:
|
||||
explicit Timer() { start(); }
|
||||
|
||||
void start() {
|
||||
clock_gettime(CLOCK_MONOTONIC, &_startTime);
|
||||
}
|
||||
void start() { clock_gettime(CLOCK_MONOTONIC, &_startTime); }
|
||||
|
||||
double getMs() {
|
||||
return (double)getNs() / 1.e6;
|
||||
}
|
||||
double getMs() { return (double)getNs() / 1.e6; }
|
||||
|
||||
int64_t getNs() {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
return (int64_t)(now.tv_nsec - _startTime.tv_nsec) + 1000000000 * (now.tv_sec - _startTime.tv_sec);
|
||||
|
||||
return (int64_t)(now.tv_nsec - _startTime.tv_nsec) +
|
||||
1000000000 * (now.tv_sec - _startTime.tv_sec);
|
||||
}
|
||||
|
||||
double getSeconds() {
|
||||
return (double)getNs() / 1.e9;
|
||||
}
|
||||
double getSeconds() { return (double)getNs() / 1.e9; }
|
||||
|
||||
struct timespec _startTime;
|
||||
};
|
||||
|
||||
|
||||
#endif //RUNTIME_TIMER_H
|
||||
#endif // RUNTIME_TIMER_H
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
struct Deci2Driver {
|
||||
u16 protocol = 0;
|
||||
void* opt = nullptr;
|
||||
void (*handler)(s32 event, s32 param, void *opt) = nullptr;
|
||||
void (*handler)(s32 event, s32 param, void* opt) = nullptr;
|
||||
u8 id = 0;
|
||||
bool active = false;
|
||||
void* recv_buffer = nullptr;
|
||||
|
||||
+16
-16
@@ -23,10 +23,7 @@
|
||||
//#include "overlord/ssound.h"
|
||||
//#include "overlord/stream.h"
|
||||
|
||||
|
||||
IOP::IOP() {
|
||||
|
||||
}
|
||||
IOP::IOP() {}
|
||||
|
||||
void IOP::send_status(IOP_Status new_status) {
|
||||
{
|
||||
@@ -38,16 +35,18 @@ void IOP::send_status(IOP_Status new_status) {
|
||||
|
||||
void IOP::wait_for_overlord_start_cmd() {
|
||||
std::unique_lock<std::mutex> lk(iop_mutex);
|
||||
if(status != IOP_WAIT_FOR_LOAD) return;
|
||||
if (status != IOP_WAIT_FOR_LOAD)
|
||||
return;
|
||||
|
||||
cv.wait(lk, [&]{return status != IOP_WAIT_FOR_LOAD;});
|
||||
cv.wait(lk, [&] { return status != IOP_WAIT_FOR_LOAD; });
|
||||
}
|
||||
|
||||
void IOP::wait_for_overlord_init_finish() {
|
||||
std::unique_lock<std::mutex> lk(iop_mutex);
|
||||
if(overlord_init_done) return;
|
||||
if (overlord_init_done)
|
||||
return;
|
||||
|
||||
cv.wait(lk, [&]{return overlord_init_done;});
|
||||
cv.wait(lk, [&] { return overlord_init_done; });
|
||||
}
|
||||
|
||||
void IOP::signal_overlord_init_finish() {
|
||||
@@ -57,7 +56,7 @@ void IOP::signal_overlord_init_finish() {
|
||||
}
|
||||
|
||||
void IOP::reset_allocator() {
|
||||
for(auto x : allocations) {
|
||||
for (auto x : allocations) {
|
||||
free(x);
|
||||
}
|
||||
allocations.clear();
|
||||
@@ -71,12 +70,12 @@ void* IOP::iop_alloc(int size) {
|
||||
|
||||
void IOP::wait_run_iop() {
|
||||
std::unique_lock<std::mutex> lk(iters_mutex);
|
||||
if(iop_iters_des > iop_iters_act) {
|
||||
if (iop_iters_des > iop_iters_act) {
|
||||
iop_iters_act++;
|
||||
return;
|
||||
}
|
||||
|
||||
iop_run_cv.wait(lk, [&]{return iop_iters_des > iop_iters_act;});
|
||||
iop_run_cv.wait(lk, [&] { return iop_iters_des > iop_iters_act; });
|
||||
iop_iters_act++;
|
||||
}
|
||||
|
||||
@@ -87,7 +86,7 @@ void IOP::kill_from_ee() {
|
||||
|
||||
void IOP::signal_run_iop() {
|
||||
std::unique_lock<std::mutex> lk(iters_mutex);
|
||||
iop_iters_des += 100; // todo, tune this
|
||||
iop_iters_des += 100; // todo, tune this
|
||||
iop_run_cv.notify_all();
|
||||
}
|
||||
|
||||
@@ -95,7 +94,7 @@ IOP::~IOP() {
|
||||
reset_allocator();
|
||||
}
|
||||
|
||||
//void launch_iop(SystemThreadInterface& interface) {
|
||||
// void launch_iop(SystemThreadInterface& interface) {
|
||||
// IOP iop;
|
||||
//
|
||||
// printf("\n\n\n[IOP] Restart!\n");
|
||||
@@ -141,13 +140,14 @@ IOP::~IOP() {
|
||||
//
|
||||
// // IOP Kernel loop
|
||||
// while(!interface.get_want_exit() && !iop.want_exit) {
|
||||
// // the IOP kernel just runs at full blast, so we only run the IOP when the EE is waiting on the IOP.
|
||||
// // the IOP kernel just runs at full blast, so we only run the IOP when the EE is waiting on
|
||||
// the IOP.
|
||||
// // Each time the EE is waiting on the IOP, it will run an iteration of the IOP kernel.
|
||||
// iop.wait_run_iop();
|
||||
// iop.kernel.dispatchAll();
|
||||
// }
|
||||
//
|
||||
// // stop all threads in the iop kernel.
|
||||
// // if the threads are not stopped nicely, we will deadlock on trying to destroy the kernel's condition variables.
|
||||
// iop.kernel.shutdown();
|
||||
// // if the threads are not stopped nicely, we will deadlock on trying to destroy the kernel's
|
||||
// condition variables. iop.kernel.shutdown();
|
||||
//}
|
||||
@@ -4,12 +4,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "IOP_Kernel.h"
|
||||
|
||||
enum IOP_Status {
|
||||
IOP_WAIT_FOR_LOAD,
|
||||
IOP_OVERLORD_INIT,
|
||||
IOP_OVERLORD_RUN,
|
||||
IOP_OVERLORD_STOP
|
||||
};
|
||||
enum IOP_Status { IOP_WAIT_FOR_LOAD, IOP_OVERLORD_INIT, IOP_OVERLORD_RUN, IOP_OVERLORD_STOP };
|
||||
|
||||
class IOP {
|
||||
public:
|
||||
@@ -25,9 +20,7 @@ class IOP {
|
||||
void wait_run_iop();
|
||||
void kill_from_ee();
|
||||
|
||||
void set_ee_main_mem(u8* mem) {
|
||||
ee_main_mem = mem;
|
||||
}
|
||||
void set_ee_main_mem(u8* mem) { ee_main_mem = mem; }
|
||||
|
||||
IOP_Status status = IOP_WAIT_FOR_LOAD;
|
||||
|
||||
@@ -40,6 +33,7 @@ class IOP {
|
||||
u64 iop_iters_des = 0;
|
||||
u64 iop_iters_act = 0;
|
||||
bool want_exit = false;
|
||||
|
||||
private:
|
||||
std::vector<void*> allocations;
|
||||
std::condition_variable cv;
|
||||
|
||||
@@ -36,8 +36,8 @@ void CodeTester::emit_return() {
|
||||
}
|
||||
|
||||
void CodeTester::emit_pop_all_gprs(bool exclude_rax) {
|
||||
for(int i = 16; i-- > 0;) {
|
||||
if(i != RAX || !exclude_rax) {
|
||||
for (int i = 16; i-- > 0;) {
|
||||
if (i != RAX || !exclude_rax) {
|
||||
emit(IGen::pop_gpr64(i));
|
||||
}
|
||||
}
|
||||
@@ -45,10 +45,9 @@ void CodeTester::emit_pop_all_gprs(bool exclude_rax) {
|
||||
|
||||
void CodeTester::emit_push_all_gprs(bool exclude_rax) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if(i != RAX || !exclude_rax) {
|
||||
if (i != RAX || !exclude_rax) {
|
||||
emit(IGen::push_gpr64(i));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,8 @@ class CodeTester {
|
||||
u64 execute();
|
||||
void clear();
|
||||
~CodeTester();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
int code_buffer_size = 0;
|
||||
int code_buffer_capacity = 0;
|
||||
u8* code_buffer = nullptr;
|
||||
|
||||
+38
-38
@@ -72,46 +72,46 @@ class IGen {
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move 32-bits of xmm to 32 bits of gpr (no sign extension).
|
||||
*/
|
||||
static Instruction movd_gpr32_xmm32(uint8_t dst, uint8_t src) {
|
||||
assert(is_gpr(dst));
|
||||
assert(is_xmm(src));
|
||||
Instruction instr(0x66);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x7e);
|
||||
instr.set_modrm_and_rex(xmm_to_id(src), dst, 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
/*!
|
||||
* Move 32-bits of xmm to 32 bits of gpr (no sign extension).
|
||||
*/
|
||||
static Instruction movd_gpr32_xmm32(uint8_t dst, uint8_t src) {
|
||||
assert(is_gpr(dst));
|
||||
assert(is_xmm(src));
|
||||
Instruction instr(0x66);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x7e);
|
||||
instr.set_modrm_and_rex(xmm_to_id(src), dst, 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move 32-bits of gpr to 32-bits of xmm (no sign extenion)
|
||||
*/
|
||||
static Instruction movd_xmm32_gpr32(uint8_t dst, uint8_t src) {
|
||||
assert(is_xmm(dst));
|
||||
assert(is_gpr(src));
|
||||
Instruction instr(0x66);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x6e);
|
||||
instr.set_modrm_and_rex(dst, xmm_to_id(src), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
/*!
|
||||
* Move 32-bits of gpr to 32-bits of xmm (no sign extenion)
|
||||
*/
|
||||
static Instruction movd_xmm32_gpr32(uint8_t dst, uint8_t src) {
|
||||
assert(is_xmm(dst));
|
||||
assert(is_gpr(src));
|
||||
Instruction instr(0x66);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x6e);
|
||||
instr.set_modrm_and_rex(dst, xmm_to_id(src), 3, false);
|
||||
instr.swap_op0_rex();
|
||||
return instr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Move 32-bits between xmm's
|
||||
*/
|
||||
static Instruction mov_xmm32_xmm32(uint8_t dst, uint8_t src) {
|
||||
assert(is_xmm(dst));
|
||||
assert(is_xmm(src));
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x10);
|
||||
instr.set_modrm_and_rex(xmm_to_id(dst), xmm_to_id(src), 3, false);
|
||||
return instr;
|
||||
}
|
||||
/*!
|
||||
* Move 32-bits between xmm's
|
||||
*/
|
||||
static Instruction mov_xmm32_xmm32(uint8_t dst, uint8_t src) {
|
||||
assert(is_xmm(dst));
|
||||
assert(is_xmm(src));
|
||||
Instruction instr(0xf3);
|
||||
instr.set_op2(0x0f);
|
||||
instr.set_op3(0x10);
|
||||
instr.set_modrm_and_rex(xmm_to_id(dst), xmm_to_id(src), 3, false);
|
||||
return instr;
|
||||
}
|
||||
//
|
||||
// //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
// // LOADS n' STORES
|
||||
|
||||
+61
-53
@@ -18,9 +18,7 @@ struct ModRM {
|
||||
uint8_t reg_op;
|
||||
uint8_t rm;
|
||||
|
||||
uint8_t operator()() const {
|
||||
return (mod << 6) | (reg_op << 3) | (rm << 0);
|
||||
}
|
||||
uint8_t operator()() const { return (mod << 6) | (reg_op << 3) | (rm << 0); }
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -29,9 +27,7 @@ struct ModRM {
|
||||
struct SIB {
|
||||
uint8_t scale, index, base;
|
||||
|
||||
uint8_t operator()() const {
|
||||
return (scale << 6) | (index << 3) | (base << 0);
|
||||
}
|
||||
uint8_t operator()() const { return (scale << 6) | (index << 3) | (base << 0); }
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -39,35 +35,33 @@ struct SIB {
|
||||
*/
|
||||
struct Imm {
|
||||
Imm() = default;
|
||||
Imm(uint8_t sz, uint64_t v) : size(sz), value(v) { }
|
||||
Imm(uint8_t sz, uint64_t v) : size(sz), value(v) {}
|
||||
uint8_t size;
|
||||
union {
|
||||
uint64_t value;
|
||||
uint8_t v_arr[8];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* The REX prefix byte
|
||||
*/
|
||||
struct REX {
|
||||
explicit REX(bool w = false, bool r = false, bool x = false, bool b = false) : W(w), R(r), X(x), B(b) { }
|
||||
explicit REX(bool w = false, bool r = false, bool x = false, bool b = false)
|
||||
: W(w), R(r), X(x), B(b) {}
|
||||
// W - 64-bit operands
|
||||
// R - reg extension
|
||||
// X - SIB i extnsion
|
||||
// B - other extension
|
||||
bool W, R, X, B;
|
||||
uint8_t operator()() const {
|
||||
return (1 << 6) | (W << 3) | (R << 2) | (X << 1) | (B << 0);
|
||||
}
|
||||
uint8_t operator()() const { return (1 << 6) | (W << 3) | (R << 2) | (X << 1) | (B << 0); }
|
||||
};
|
||||
|
||||
/*!
|
||||
* A high-level description of an x86-64 opcode. It can emit itself.
|
||||
*/
|
||||
struct Instruction {
|
||||
Instruction(uint8_t opcode) : op(opcode) { }
|
||||
Instruction(uint8_t opcode) : op(opcode) {}
|
||||
uint8_t op;
|
||||
|
||||
bool op2_set = false;
|
||||
@@ -110,7 +104,8 @@ struct Instruction {
|
||||
* Move opcode byte 0 to before the rex prefix.
|
||||
*/
|
||||
void swap_op0_rex() {
|
||||
if(!set_rex) return;
|
||||
if (!set_rex)
|
||||
return;
|
||||
auto temp = op;
|
||||
op = m_rex;
|
||||
m_rex = temp;
|
||||
@@ -157,12 +152,12 @@ struct Instruction {
|
||||
void set_modrm_and_rex(uint8_t reg, uint8_t rm, uint8_t mod, bool rex_w = false) {
|
||||
bool rex_b = false, rex_r = false;
|
||||
|
||||
if(rm >= 8) {
|
||||
if (rm >= 8) {
|
||||
rm -= 8;
|
||||
rex_b = true;
|
||||
}
|
||||
|
||||
if(reg >= 8) {
|
||||
if (reg >= 8) {
|
||||
reg -= 8;
|
||||
rex_r = true;
|
||||
}
|
||||
@@ -174,7 +169,7 @@ struct Instruction {
|
||||
|
||||
set(modrm);
|
||||
|
||||
if(rex_b || rex_w || rex_r) {
|
||||
if (rex_b || rex_w || rex_r) {
|
||||
set(REX(rex_w, rex_r, false, rex_b));
|
||||
}
|
||||
}
|
||||
@@ -186,12 +181,12 @@ struct Instruction {
|
||||
void set_modrm_and_rex_for_addr(uint8_t reg, uint8_t rm, uint8_t mod, bool rex_w = false) {
|
||||
bool rex_b = false, rex_r = false;
|
||||
|
||||
if(rm >= 8) {
|
||||
if (rm >= 8) {
|
||||
rm -= 8;
|
||||
rex_b = true;
|
||||
}
|
||||
|
||||
if(reg >= 8) {
|
||||
if (reg >= 8) {
|
||||
reg -= 8;
|
||||
rex_r = true;
|
||||
}
|
||||
@@ -203,7 +198,7 @@ struct Instruction {
|
||||
|
||||
set(modrm);
|
||||
|
||||
if(rm == 4) {
|
||||
if (rm == 4) {
|
||||
SIB sib;
|
||||
sib.scale = 0;
|
||||
sib.base = 4;
|
||||
@@ -212,13 +207,13 @@ struct Instruction {
|
||||
set(sib);
|
||||
}
|
||||
|
||||
if(rex_b || rex_w || rex_r) {
|
||||
if (rex_b || rex_w || rex_r) {
|
||||
set(REX(rex_w, rex_r, false, rex_b));
|
||||
}
|
||||
}
|
||||
|
||||
void add_rex() {
|
||||
if(!set_rex) {
|
||||
if (!set_rex) {
|
||||
set(REX());
|
||||
}
|
||||
}
|
||||
@@ -230,7 +225,7 @@ struct Instruction {
|
||||
ModRM modrm;
|
||||
|
||||
bool rex_r = false;
|
||||
if(reg >= 8) {
|
||||
if (reg >= 8) {
|
||||
reg -= 8;
|
||||
rex_r = true;
|
||||
}
|
||||
@@ -238,13 +233,13 @@ struct Instruction {
|
||||
|
||||
modrm.mod = mod;
|
||||
|
||||
modrm.rm = 4; // use sib
|
||||
modrm.rm = 4; // use sib
|
||||
|
||||
SIB sib;
|
||||
sib.scale = 0;
|
||||
sib.index = 4;
|
||||
bool rex_b = false;
|
||||
if(rm >= 8) {
|
||||
if (rm >= 8) {
|
||||
rex_b = true;
|
||||
rm -= 8;
|
||||
}
|
||||
@@ -254,25 +249,30 @@ struct Instruction {
|
||||
set(modrm);
|
||||
set(sib);
|
||||
|
||||
if(rex_r || rex_w || rex_b) {
|
||||
if (rex_r || rex_w || rex_b) {
|
||||
set(REX(rex_w, rex_r, false, rex_b));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Get the position of the disp immediate relative to the start of the instruction
|
||||
*/
|
||||
int offset_of_disp() const {
|
||||
if(is_null) return 0;
|
||||
if (is_null)
|
||||
return 0;
|
||||
assert(set_disp_imm);
|
||||
int offset = 0;
|
||||
if(set_rex) offset++;
|
||||
offset++; // opcode
|
||||
if(op2_set) offset++;
|
||||
if(op3_set) offset++;
|
||||
if(set_modrm) offset++;
|
||||
if(set_sib) offset++;
|
||||
if (set_rex)
|
||||
offset++;
|
||||
offset++; // opcode
|
||||
if (op2_set)
|
||||
offset++;
|
||||
if (op3_set)
|
||||
offset++;
|
||||
if (set_modrm)
|
||||
offset++;
|
||||
if (set_sib)
|
||||
offset++;
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -280,16 +280,23 @@ struct Instruction {
|
||||
* Get the position of the imm immediate relative to the start of the instruction
|
||||
*/
|
||||
int offset_of_imm() const {
|
||||
if(is_null) return 0;
|
||||
if (is_null)
|
||||
return 0;
|
||||
assert(set_imm);
|
||||
int offset = 0;
|
||||
if(set_rex) offset++;
|
||||
offset++; // opcode
|
||||
if(op2_set) offset++;
|
||||
if(op3_set) offset++;
|
||||
if(set_modrm) offset++;
|
||||
if(set_sib) offset++;
|
||||
if(set_disp_imm) offset += disp.size;
|
||||
if (set_rex)
|
||||
offset++;
|
||||
offset++; // opcode
|
||||
if (op2_set)
|
||||
offset++;
|
||||
if (op3_set)
|
||||
offset++;
|
||||
if (set_modrm)
|
||||
offset++;
|
||||
if (set_sib)
|
||||
offset++;
|
||||
if (set_disp_imm)
|
||||
offset += disp.size;
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -297,44 +304,45 @@ struct Instruction {
|
||||
* Emit into a buffer and return how many bytes written (can be zero)
|
||||
*/
|
||||
uint8_t emit(uint8_t* buffer) const {
|
||||
if(is_null) return 0;
|
||||
if (is_null)
|
||||
return 0;
|
||||
uint8_t count = 0;
|
||||
if(set_rex) {
|
||||
if (set_rex) {
|
||||
buffer[count++] = m_rex;
|
||||
}
|
||||
|
||||
buffer[count++] = op;
|
||||
|
||||
if(op2_set) {
|
||||
if (op2_set) {
|
||||
buffer[count++] = op2;
|
||||
}
|
||||
|
||||
if(op3_set) {
|
||||
if (op3_set) {
|
||||
buffer[count++] = op3;
|
||||
}
|
||||
|
||||
if(set_modrm) {
|
||||
if (set_modrm) {
|
||||
buffer[count++] = m_modrm;
|
||||
}
|
||||
|
||||
if(set_sib) {
|
||||
if (set_sib) {
|
||||
buffer[count++] = m_sib;
|
||||
}
|
||||
|
||||
if(set_disp_imm) {
|
||||
for(int i = 0; i < disp.size; i++) {
|
||||
if (set_disp_imm) {
|
||||
for (int i = 0; i < disp.size; i++) {
|
||||
buffer[count++] = disp.v_arr[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(set_imm) {
|
||||
for(int i = 0; i < imm.size; i++) {
|
||||
if (set_imm) {
|
||||
for (int i = 0; i < imm.size; i++) {
|
||||
buffer[count++] = imm.v_arr[i];
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace goal
|
||||
|
||||
#endif // JAK1_INSTRUCTION_H
|
||||
|
||||
@@ -17,4 +17,4 @@ u8 xmm_to_id(u8 reg) {
|
||||
return reg - 16;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace goal
|
||||
@@ -12,8 +12,7 @@
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include "game/system/deci_common.h" // todo, move me!
|
||||
|
||||
#include "game/system/deci_common.h" // todo, move me!
|
||||
|
||||
class Deci2Server {
|
||||
public:
|
||||
@@ -31,7 +30,6 @@ class Deci2Server {
|
||||
|
||||
void run();
|
||||
|
||||
|
||||
private:
|
||||
void accept_thread_func();
|
||||
bool kill_accept_thread = false;
|
||||
@@ -52,6 +50,4 @@ class Deci2Server {
|
||||
int* d2_driver_count = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // JAK1_DECI2SERVER_H
|
||||
|
||||
@@ -25,12 +25,11 @@ class Listener {
|
||||
bool is_connected() const;
|
||||
void disconnect();
|
||||
|
||||
|
||||
private:
|
||||
char* m_buffer = nullptr; //! buffer for incoming messages
|
||||
bool m_connected = false; //! do we think we are connected?
|
||||
bool receive_thread_running = false; //! is the receive thread unjoined?
|
||||
int socket_fd = -1; //! socket
|
||||
char* m_buffer = nullptr; //! buffer for incoming messages
|
||||
bool m_connected = false; //! do we think we are connected?
|
||||
bool receive_thread_running = false; //! is the receive thread unjoined?
|
||||
int socket_fd = -1; //! socket
|
||||
bool got_ack = false;
|
||||
bool waiting_for_ack = false;
|
||||
|
||||
@@ -41,7 +40,6 @@ class Listener {
|
||||
std::vector<std::string> message_record;
|
||||
char ack_recv_buff[512];
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace listener
|
||||
|
||||
#endif // JAK1_LISTENER_H
|
||||
|
||||
@@ -11,4 +11,3 @@ int main(int argc, char** argv) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,4 +13,4 @@ namespace util {
|
||||
bool is_printable_char(char c) {
|
||||
return c >= ' ' && c <= '~';
|
||||
}
|
||||
}
|
||||
} // namespace util
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
export NEXT_DIR=$DIR
|
||||
$DIR/build/test/goalc-test "$@"
|
||||
$DIR/build/test/goalc-test --gtest_color=yes --gtest_brief=1 "$@"
|
||||
@@ -135,17 +135,17 @@ TEST(CodeTester, xmm_move) {
|
||||
CodeTester tester;
|
||||
tester.init_code_buffer(256);
|
||||
|
||||
for(auto constant : u32_constants) {
|
||||
for(int r1 = 0; r1 < 16; r1++) {
|
||||
if(r1 == RSP) {
|
||||
for (auto constant : u32_constants) {
|
||||
for (int r1 = 0; r1 < 16; r1++) {
|
||||
if (r1 == RSP) {
|
||||
continue;
|
||||
}
|
||||
for(int r2 = 0; r2 < 16; r2++) {
|
||||
if(r2 == RSP) {
|
||||
for (int r2 = 0; r2 < 16; r2++) {
|
||||
if (r2 == RSP) {
|
||||
continue;
|
||||
}
|
||||
for(int r3 = 0; r3 < 16; r3++) {
|
||||
for(int r4 = 0; r4 < 16; r4++) {
|
||||
for (int r3 = 0; r3 < 16; r3++) {
|
||||
for (int r4 = 0; r4 < 16; r4++) {
|
||||
tester.clear();
|
||||
tester.emit_push_all_gprs(true);
|
||||
// move constant to gpr
|
||||
|
||||
@@ -262,8 +262,7 @@ TEST(Kernel, itoa_base_16) {
|
||||
EXPECT_EQ("1", std::string(buffer));
|
||||
|
||||
kitoa(buffer, -1, 16, -1, ' ', 0);
|
||||
EXPECT_EQ("ffffffffffffffff",
|
||||
std::string(buffer));
|
||||
EXPECT_EQ("ffffffffffffffff", std::string(buffer));
|
||||
|
||||
kitoa(buffer, -1, 16, 5, ' ', 0);
|
||||
EXPECT_EQ("-fffff", std::string(buffer));
|
||||
@@ -281,8 +280,7 @@ TEST(Kernel, itoa_base_16) {
|
||||
EXPECT_EQ("jjjjbadbeef", std::string(buffer));
|
||||
|
||||
kitoa(buffer, INT64_MIN, 16, 0, ' ', 0);
|
||||
EXPECT_EQ("8000000000000000",
|
||||
std::string(buffer));
|
||||
EXPECT_EQ("8000000000000000", std::string(buffer));
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -342,7 +340,6 @@ TEST(Kernel, PrintBuffer) {
|
||||
// more complicated tests for format will be done from within GOAL.
|
||||
}
|
||||
|
||||
|
||||
TEST(Kernel, HashTable) {
|
||||
constexpr int size = 32 * 1024 * 1024;
|
||||
auto mem = new u8[size];
|
||||
@@ -359,7 +356,7 @@ TEST(Kernel, HashTable) {
|
||||
std::unordered_map<std::string, u32> symbol_locations;
|
||||
std::unordered_set<u32> unique_locations;
|
||||
|
||||
for(auto name : all_syms) {
|
||||
for (auto name : all_syms) {
|
||||
auto loc = intern_from_c(name).offset;
|
||||
symbol_locations[name] = loc;
|
||||
unique_locations.insert(loc);
|
||||
@@ -368,7 +365,7 @@ TEST(Kernel, HashTable) {
|
||||
EXPECT_EQ(7941, symbol_locations.size());
|
||||
EXPECT_EQ(7941, unique_locations.size());
|
||||
|
||||
for(auto name : all_syms) {
|
||||
for (auto name : all_syms) {
|
||||
EXPECT_EQ(symbol_locations.at(name), intern_from_c(name).offset);
|
||||
}
|
||||
|
||||
@@ -379,11 +376,10 @@ TEST(Kernel, HashTable) {
|
||||
|
||||
// expect no crc32 hash collisions. This doesn't matter, but it's nice to know.
|
||||
std::unordered_set<u32> crc32s;
|
||||
for(auto name : all_syms) {
|
||||
for (auto name : all_syms) {
|
||||
crc32s.insert(crc32((const u8*)name, strlen(name)));
|
||||
}
|
||||
EXPECT_EQ(7941, crc32s.size());
|
||||
|
||||
delete[] mem;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace {
|
||||
bool always_false() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(Listener, ListenerCreation) {
|
||||
listener::Listener l;
|
||||
@@ -23,7 +23,7 @@ TEST(Listener, DeciInit) {
|
||||
EXPECT_TRUE(s.init());
|
||||
}
|
||||
|
||||
//TEST(Listener, TwoDeciServers) {
|
||||
// TEST(Listener, TwoDeciServers) {
|
||||
// Deci2Server s1, s2;
|
||||
// EXPECT_TRUE(s1.init());
|
||||
// EXPECT_TRUE(s2.init());
|
||||
@@ -47,7 +47,7 @@ TEST(Listener, DeciCheckNoListener) {
|
||||
}
|
||||
|
||||
TEST(Listener, DeciThenListener) {
|
||||
for(int i = 0; i < 10; i++) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Deci2Server s(always_false);
|
||||
EXPECT_TRUE(s.init());
|
||||
EXPECT_FALSE(s.check_for_listener());
|
||||
@@ -58,8 +58,8 @@ TEST(Listener, DeciThenListener) {
|
||||
EXPECT_FALSE(s.check_for_listener());
|
||||
EXPECT_TRUE(l.connect_to_target());
|
||||
// kind of a hack.
|
||||
while(!s.check_for_listener()) {
|
||||
printf("...\n");
|
||||
while (!s.check_for_listener()) {
|
||||
// printf("...\n");
|
||||
}
|
||||
|
||||
EXPECT_TRUE(s.check_for_listener());
|
||||
@@ -67,7 +67,7 @@ TEST(Listener, DeciThenListener) {
|
||||
}
|
||||
|
||||
TEST(Listener, DeciThenListener2) {
|
||||
for(int i = 0; i < 10; i++) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Deci2Server s(always_false);
|
||||
EXPECT_TRUE(s.init());
|
||||
EXPECT_FALSE(s.check_for_listener());
|
||||
@@ -81,14 +81,14 @@ TEST(Listener, DeciThenListener2) {
|
||||
}
|
||||
|
||||
TEST(Listener, ListenerThenDeci) {
|
||||
for(int i = 0; i < 10; i++) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Listener l;
|
||||
EXPECT_FALSE(l.connect_to_target());
|
||||
Deci2Server s(always_false);
|
||||
EXPECT_TRUE(s.init());
|
||||
EXPECT_FALSE(s.check_for_listener());
|
||||
EXPECT_TRUE(l.connect_to_target());
|
||||
while(!s.check_for_listener()) {
|
||||
while (!s.check_for_listener()) {
|
||||
printf("...\n");
|
||||
}
|
||||
}
|
||||
@@ -102,8 +102,8 @@ TEST(Listener, ListenerMultipleDecis) {
|
||||
EXPECT_TRUE(s.init());
|
||||
EXPECT_FALSE(s.check_for_listener());
|
||||
EXPECT_TRUE(l.connect_to_target());
|
||||
while(!s.check_for_listener()) {
|
||||
printf("...\n");
|
||||
while (!s.check_for_listener()) {
|
||||
// printf("...\n");
|
||||
}
|
||||
l.disconnect();
|
||||
}
|
||||
@@ -113,10 +113,9 @@ TEST(Listener, ListenerMultipleDecis) {
|
||||
EXPECT_TRUE(s.init());
|
||||
EXPECT_FALSE(s.check_for_listener());
|
||||
EXPECT_TRUE(l.connect_to_target());
|
||||
while(!s.check_for_listener()) {
|
||||
printf("...\n");
|
||||
while (!s.check_for_listener()) {
|
||||
// printf("...\n");
|
||||
}
|
||||
l.disconnect();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -316,8 +316,7 @@ TEST(GoosReader, TopLevel) {
|
||||
|
||||
TEST(GoosReader, FromFile) {
|
||||
Reader reader;
|
||||
auto result =
|
||||
reader.read_from_file(util::combine_path({"test", "test_reader_file0.gc"})).print();
|
||||
auto result = reader.read_from_file(util::combine_path({"test", "test_reader_file0.gc"})).print();
|
||||
EXPECT_TRUE(result == "(top-level (1 2 3 4))");
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ TEST(TypeSystem, DefaultMethods) {
|
||||
TypeSystem ts;
|
||||
ts.add_builtin_types();
|
||||
|
||||
|
||||
ts.assert_method_id("object", "new", 0);
|
||||
ts.assert_method_id("object", "delete", 1);
|
||||
ts.assert_method_id("object", "print", 2);
|
||||
|
||||
+404
@@ -0,0 +1,404 @@
|
||||
#!/usr/bin/env python
|
||||
"""A wrapper script around clang-format, suitable for linting multiple files
|
||||
and to use for continuous integration.
|
||||
|
||||
This is an alternative API for the clang-format command line.
|
||||
It runs over multiple files and directories in parallel.
|
||||
A diff output is produced and a sensible exit code is returned.
|
||||
|
||||
See - https://github.com/Sarcasm/run-clang-format
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import argparse
|
||||
import codecs
|
||||
import difflib
|
||||
import fnmatch
|
||||
import io
|
||||
import errno
|
||||
import multiprocessing
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from functools import partial
|
||||
|
||||
try:
|
||||
from subprocess import DEVNULL # py3k
|
||||
except ImportError:
|
||||
DEVNULL = open(os.devnull, "wb")
|
||||
|
||||
|
||||
DEFAULT_EXTENSIONS = 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx'
|
||||
DEFAULT_CLANG_FORMAT_IGNORE = '.clang-format-ignore'
|
||||
|
||||
|
||||
class ExitStatus:
|
||||
SUCCESS = 0
|
||||
DIFF = 1
|
||||
TROUBLE = 2
|
||||
|
||||
def excludes_from_file(ignore_file):
|
||||
excludes = []
|
||||
try:
|
||||
with io.open(ignore_file, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
if line.startswith('#'):
|
||||
# ignore comments
|
||||
continue
|
||||
pattern = line.rstrip()
|
||||
if not pattern:
|
||||
# allow empty lines
|
||||
continue
|
||||
excludes.append(pattern)
|
||||
except EnvironmentError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
return excludes;
|
||||
|
||||
def list_files(files, recursive=False, extensions=None, exclude=None):
|
||||
if extensions is None:
|
||||
extensions = []
|
||||
if exclude is None:
|
||||
exclude = []
|
||||
|
||||
out = []
|
||||
for file in files:
|
||||
if recursive and os.path.isdir(file):
|
||||
for dirpath, dnames, fnames in os.walk(file):
|
||||
fpaths = [os.path.join(dirpath, fname) for fname in fnames]
|
||||
for pattern in exclude:
|
||||
# os.walk() supports trimming down the dnames list
|
||||
# by modifying it in-place,
|
||||
# to avoid unnecessary directory listings.
|
||||
dnames[:] = [
|
||||
x for x in dnames
|
||||
if
|
||||
not fnmatch.fnmatch(os.path.join(dirpath, x), pattern)
|
||||
]
|
||||
fpaths = [
|
||||
x for x in fpaths if not fnmatch.fnmatch(x, pattern)
|
||||
]
|
||||
for f in fpaths:
|
||||
ext = os.path.splitext(f)[1][1:]
|
||||
if ext in extensions:
|
||||
out.append(f)
|
||||
else:
|
||||
out.append(file)
|
||||
return out
|
||||
|
||||
|
||||
def make_diff(file, original, reformatted):
|
||||
return list(
|
||||
difflib.unified_diff(
|
||||
original,
|
||||
reformatted,
|
||||
fromfile='{}\t(original)'.format(file),
|
||||
tofile='{}\t(reformatted)'.format(file),
|
||||
n=3))
|
||||
|
||||
|
||||
class DiffError(Exception):
|
||||
def __init__(self, message, errs=None):
|
||||
super(DiffError, self).__init__(message)
|
||||
self.errs = errs or []
|
||||
|
||||
|
||||
class UnexpectedError(Exception):
|
||||
def __init__(self, message, exc=None):
|
||||
super(UnexpectedError, self).__init__(message)
|
||||
self.formatted_traceback = traceback.format_exc()
|
||||
self.exc = exc
|
||||
|
||||
|
||||
def run_clang_format_diff_wrapper(args, file):
|
||||
try:
|
||||
ret = run_clang_format_diff(args, file)
|
||||
return ret
|
||||
except DiffError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise UnexpectedError('{}: {}: {}'.format(file, e.__class__.__name__,
|
||||
e), e)
|
||||
|
||||
|
||||
def run_clang_format_diff(args, file):
|
||||
try:
|
||||
with io.open(file, 'r', encoding='utf-8') as f:
|
||||
original = f.readlines()
|
||||
except IOError as exc:
|
||||
raise DiffError(str(exc))
|
||||
|
||||
if args.in_place:
|
||||
invocation = [args.clang_format_executable, '-i', file]
|
||||
else:
|
||||
invocation = [args.clang_format_executable, file]
|
||||
|
||||
if args.dry_run:
|
||||
print(" ".join(invocation))
|
||||
return [], []
|
||||
|
||||
# Use of utf-8 to decode the process output.
|
||||
#
|
||||
# Hopefully, this is the correct thing to do.
|
||||
#
|
||||
# It's done due to the following assumptions (which may be incorrect):
|
||||
# - clang-format will returns the bytes read from the files as-is,
|
||||
# without conversion, and it is already assumed that the files use utf-8.
|
||||
# - if the diagnostics were internationalized, they would use utf-8:
|
||||
# > Adding Translations to Clang
|
||||
# >
|
||||
# > Not possible yet!
|
||||
# > Diagnostic strings should be written in UTF-8,
|
||||
# > the client can translate to the relevant code page if needed.
|
||||
# > Each translation completely replaces the format string
|
||||
# > for the diagnostic.
|
||||
# > -- http://clang.llvm.org/docs/InternalsManual.html#internals-diag-translation
|
||||
#
|
||||
# It's not pretty, due to Python 2 & 3 compatibility.
|
||||
encoding_py3 = {}
|
||||
if sys.version_info[0] >= 3:
|
||||
encoding_py3['encoding'] = 'utf-8'
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
invocation,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
**encoding_py3)
|
||||
except OSError as exc:
|
||||
raise DiffError(
|
||||
"Command '{}' failed to start: {}".format(
|
||||
subprocess.list2cmdline(invocation), exc
|
||||
)
|
||||
)
|
||||
proc_stdout = proc.stdout
|
||||
proc_stderr = proc.stderr
|
||||
if sys.version_info[0] < 3:
|
||||
# make the pipes compatible with Python 3,
|
||||
# reading lines should output unicode
|
||||
encoding = 'utf-8'
|
||||
proc_stdout = codecs.getreader(encoding)(proc_stdout)
|
||||
proc_stderr = codecs.getreader(encoding)(proc_stderr)
|
||||
# hopefully the stderr pipe won't get full and block the process
|
||||
outs = list(proc_stdout.readlines())
|
||||
errs = list(proc_stderr.readlines())
|
||||
proc.wait()
|
||||
if proc.returncode:
|
||||
raise DiffError(
|
||||
"Command '{}' returned non-zero exit status {}".format(
|
||||
subprocess.list2cmdline(invocation), proc.returncode
|
||||
),
|
||||
errs,
|
||||
)
|
||||
if args.in_place:
|
||||
return [], errs
|
||||
return make_diff(file, original, outs), errs
|
||||
|
||||
|
||||
def bold_red(s):
|
||||
return '\x1b[1m\x1b[31m' + s + '\x1b[0m'
|
||||
|
||||
|
||||
def colorize(diff_lines):
|
||||
def bold(s):
|
||||
return '\x1b[1m' + s + '\x1b[0m'
|
||||
|
||||
def cyan(s):
|
||||
return '\x1b[36m' + s + '\x1b[0m'
|
||||
|
||||
def green(s):
|
||||
return '\x1b[32m' + s + '\x1b[0m'
|
||||
|
||||
def red(s):
|
||||
return '\x1b[31m' + s + '\x1b[0m'
|
||||
|
||||
for line in diff_lines:
|
||||
if line[:4] in ['--- ', '+++ ']:
|
||||
yield bold(line)
|
||||
elif line.startswith('@@ '):
|
||||
yield cyan(line)
|
||||
elif line.startswith('+'):
|
||||
yield green(line)
|
||||
elif line.startswith('-'):
|
||||
yield red(line)
|
||||
else:
|
||||
yield line
|
||||
|
||||
|
||||
def print_diff(diff_lines, use_color):
|
||||
if use_color:
|
||||
diff_lines = colorize(diff_lines)
|
||||
if sys.version_info[0] < 3:
|
||||
sys.stdout.writelines((l.encode('utf-8') for l in diff_lines))
|
||||
else:
|
||||
sys.stdout.writelines(diff_lines)
|
||||
|
||||
|
||||
def print_trouble(prog, message, use_colors):
|
||||
error_text = 'error:'
|
||||
if use_colors:
|
||||
error_text = bold_red(error_text)
|
||||
print("{}: {} {}".format(prog, error_text, message), file=sys.stderr)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
'--clang-format-executable',
|
||||
metavar='EXECUTABLE',
|
||||
help='path to the clang-format executable',
|
||||
default='clang-format')
|
||||
parser.add_argument(
|
||||
'--extensions',
|
||||
help='comma separated list of file extensions (default: {})'.format(
|
||||
DEFAULT_EXTENSIONS),
|
||||
default=DEFAULT_EXTENSIONS)
|
||||
parser.add_argument(
|
||||
'-r',
|
||||
'--recursive',
|
||||
action='store_true',
|
||||
help='run recursively over directories')
|
||||
parser.add_argument(
|
||||
'-d',
|
||||
'--dry-run',
|
||||
action='store_true',
|
||||
help='just print the list of files')
|
||||
parser.add_argument(
|
||||
'-i',
|
||||
'--in-place',
|
||||
action='store_true',
|
||||
help='format file instead of printing differences')
|
||||
parser.add_argument('files', metavar='file', nargs='+')
|
||||
parser.add_argument(
|
||||
'-q',
|
||||
'--quiet',
|
||||
action='store_true',
|
||||
help="disable output, useful for the exit code")
|
||||
parser.add_argument(
|
||||
'-j',
|
||||
metavar='N',
|
||||
type=int,
|
||||
default=0,
|
||||
help='run N clang-format jobs in parallel'
|
||||
' (default number of cpus + 1)')
|
||||
parser.add_argument(
|
||||
'--color',
|
||||
default='auto',
|
||||
choices=['auto', 'always', 'never'],
|
||||
help='show colored diff (default: auto)')
|
||||
parser.add_argument(
|
||||
'-e',
|
||||
'--exclude',
|
||||
metavar='PATTERN',
|
||||
action='append',
|
||||
default=[],
|
||||
help='exclude paths matching the given glob-like pattern(s)'
|
||||
' from recursive search')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# use default signal handling, like diff return SIGINT value on ^C
|
||||
# https://bugs.python.org/issue14229#msg156446
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
try:
|
||||
signal.SIGPIPE
|
||||
except AttributeError:
|
||||
# compatibility, SIGPIPE does not exist on Windows
|
||||
pass
|
||||
else:
|
||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
||||
|
||||
colored_stdout = False
|
||||
colored_stderr = False
|
||||
if args.color == 'always':
|
||||
colored_stdout = True
|
||||
colored_stderr = True
|
||||
elif args.color == 'auto':
|
||||
colored_stdout = sys.stdout.isatty()
|
||||
colored_stderr = sys.stderr.isatty()
|
||||
|
||||
version_invocation = [args.clang_format_executable, str("--version")]
|
||||
try:
|
||||
subprocess.check_call(version_invocation, stdout=DEVNULL)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
return ExitStatus.TROUBLE
|
||||
except OSError as e:
|
||||
print_trouble(
|
||||
parser.prog,
|
||||
"Command '{}' failed to start: {}".format(
|
||||
subprocess.list2cmdline(version_invocation), e
|
||||
),
|
||||
use_colors=colored_stderr,
|
||||
)
|
||||
return ExitStatus.TROUBLE
|
||||
|
||||
retcode = ExitStatus.SUCCESS
|
||||
|
||||
excludes = excludes_from_file(DEFAULT_CLANG_FORMAT_IGNORE)
|
||||
excludes.extend(args.exclude)
|
||||
|
||||
files = list_files(
|
||||
args.files,
|
||||
recursive=args.recursive,
|
||||
exclude=excludes,
|
||||
extensions=args.extensions.split(','))
|
||||
|
||||
if not files:
|
||||
return
|
||||
|
||||
njobs = args.j
|
||||
if njobs == 0:
|
||||
njobs = multiprocessing.cpu_count() + 1
|
||||
njobs = min(len(files), njobs)
|
||||
|
||||
if njobs == 1:
|
||||
# execute directly instead of in a pool,
|
||||
# less overhead, simpler stacktraces
|
||||
it = (run_clang_format_diff_wrapper(args, file) for file in files)
|
||||
pool = None
|
||||
else:
|
||||
pool = multiprocessing.Pool(njobs)
|
||||
it = pool.imap_unordered(
|
||||
partial(run_clang_format_diff_wrapper, args), files)
|
||||
pool.close()
|
||||
while True:
|
||||
try:
|
||||
outs, errs = next(it)
|
||||
except StopIteration:
|
||||
break
|
||||
except DiffError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
retcode = ExitStatus.TROUBLE
|
||||
sys.stderr.writelines(e.errs)
|
||||
except UnexpectedError as e:
|
||||
print_trouble(parser.prog, str(e), use_colors=colored_stderr)
|
||||
sys.stderr.write(e.formatted_traceback)
|
||||
retcode = ExitStatus.TROUBLE
|
||||
# stop at the first unexpected error,
|
||||
# something could be very wrong,
|
||||
# don't process all files unnecessarily
|
||||
if pool:
|
||||
pool.terminate()
|
||||
break
|
||||
else:
|
||||
sys.stderr.writelines(errs)
|
||||
if outs == []:
|
||||
continue
|
||||
if not args.quiet:
|
||||
print_diff(outs, use_color=colored_stdout)
|
||||
if retcode == ExitStatus.SUCCESS:
|
||||
retcode = ExitStatus.DIFF
|
||||
if pool:
|
||||
pool.join()
|
||||
return retcode
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user