mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 00:57:44 -04:00
Merge pull request #4 from xTVaser/windows-nodeci
Current Windows Build
This commit is contained in:
commit
44f0fd054d
5
.editorconfig
Normal file
5
.editorconfig
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Rules in this file were initially inferred by Visual Studio IntelliCode from the C:\Users\xtvas\Repositories\jak-project codebase based on best match to current usage at 2020-08-28
|
||||
# You can modify the rules from these initially generated values to suit your own policies
|
||||
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference
|
||||
[*.cs]
|
||||
|
3
.github/workflows/linux-workflow.yaml
vendored
3
.github/workflows/linux-workflow.yaml
vendored
|
@ -1,5 +1,5 @@
|
|||
name: Linux Workflow
|
||||
on: [push]
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
@ -20,6 +20,7 @@ jobs:
|
|||
make -j
|
||||
- name: Test Project with gTest
|
||||
run: ./test.sh
|
||||
timeout-minutes: 5
|
||||
- name: Check Clang-Formatting
|
||||
run: |
|
||||
chmod +x ./third-party/run-clang-format/run-clang-format.py
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
# for clion
|
||||
cmake-build-debug/*
|
||||
.idea/*
|
||||
build/*
|
||||
build/*
|
3
.vs/.gitignore
vendored
Normal file
3
.vs/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!.gitignore
|
||||
!launch.vs.json
|
45
.vs/launch.vs.json
Normal file
45
.vs/launch.vs.json
Normal file
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
// https://docs.microsoft.com/en-us/cpp/build/launch-vs-schema-reference-cpp?view=vs-2019
|
||||
"version": "0.2.1",
|
||||
"defaults": {},
|
||||
"configurations": [
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Run Tests - Summary",
|
||||
"args": ["--gtest_brief=1"],
|
||||
"env": {
|
||||
"NEXT_DIR": "${projectDir}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Run Tests - Verbose",
|
||||
"args": ["--gtest_brief=0"],
|
||||
"env": {
|
||||
"NEXT_DIR": "${projectDir}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "gk.exe (bin\\gk.exe)",
|
||||
"name": "Run Game"
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc.exe (bin\\goalc.exe)",
|
||||
"name": "Build Compiler"
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "decompiler.exe (bin\\decompiler.exe)",
|
||||
"name": "Build Decompiler"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -4,11 +4,34 @@ project(jak)
|
|||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
# Set default compile flags for GCC
|
||||
# optimization level can be set here. Note that game/ overwrites this for building game C++ code.
|
||||
set(CMAKE_CXX_FLAGS "-O0 -ggdb -Wall \
|
||||
-Wextra -Wcast-align -Wcast-qual -Wdisabled-optimization -Wformat=2 \
|
||||
-Winit-self -Wmissing-include-dirs -Woverloaded-virtual \
|
||||
-Wredundant-decls -Wshadow -Wsign-promo ")
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
message(STATUS "GCC detected, adding compile flags")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
-Wall \
|
||||
-Winit-self \
|
||||
-Wextra \
|
||||
-Wcast-align \
|
||||
-Wcast-qual \
|
||||
-Wdisabled-optimization \
|
||||
-Wformat=2 \
|
||||
-Wmissing-include-dirs \
|
||||
-Woverloaded-virtual \
|
||||
-Wredundant-decls \
|
||||
-Wshadow \
|
||||
-Wsign-promo")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "/EHsc")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
IF (WIN32)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
ENDIF()
|
||||
|
||||
# includes relative to top level jak-project folder
|
||||
include_directories(./)
|
||||
|
@ -38,4 +61,9 @@ add_subdirectory(test)
|
|||
add_subdirectory(third-party/minilzo)
|
||||
|
||||
# build format library
|
||||
add_subdirectory(third-party/fmt)
|
||||
add_subdirectory(third-party/fmt)
|
||||
|
||||
# windows memory management lib
|
||||
IF (WIN32)
|
||||
add_subdirectory(third-party/mman)
|
||||
ENDIF()
|
||||
|
|
22
CMakeSettings.json
Normal file
22
CMakeSettings.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"variables": [
|
||||
{
|
||||
"name": "INSTALL_GTEST",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
215
README.md
215
README.md
|
@ -1,22 +1,96 @@
|
|||
Build Status
|
||||
--------------
|
||||
# Jak Project
|
||||
![Linux Workflow](https://github.com/water111/jak-project/workflows/Linux%20Workflow/badge.svg?branch=master)
|
||||
|
||||
Project Structure
|
||||
----------------------
|
||||
Requirements:
|
||||
## Table of Contents
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
- [Jak Project](#jak-project)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Requirements](#requirements)
|
||||
- [Getting Started - Linux (Ubuntu)](#getting-started---linux-ubuntu)
|
||||
- [Getting Started - Windows](#getting-started---windows)
|
||||
- [Project Layout](#project-layout)
|
||||
- [Design](#design)
|
||||
- [Current State](#current-state)
|
||||
- [Coding Guidelines](#coding-guidelines)
|
||||
- [TODOs](#todos)
|
||||
- [Project Description](#project-description)
|
||||
- [GOAL Decompiler](#goal-decompiler)
|
||||
- [GOAL Runtime](#goal-runtime)
|
||||
- [GOAL Compiler](#goal-compiler)
|
||||
- [Asset Extraction Tool](#asset-extraction-tool)
|
||||
- [Asset Packing Tool](#asset-packing-tool)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## Requirements
|
||||
|
||||
- `cmake` for build system
|
||||
- `clang-format` for formatting code (there is already a `.clang-format` provided)
|
||||
- `gtest` for testing. (Run `git submodule update --init --recursive` to check out the repository)
|
||||
- `nasm` for assembling x86. There isn't much x86 assembly so if there's a better way to do this for windows, we can change.
|
||||
- `nasm` for assembling x86
|
||||
- Third party libraries (`nlohmann/json`, `minilzo`, and `linenoise`) are provided in the `third-party` folder
|
||||
|
||||
Setup (for Ubuntu):
|
||||
```
|
||||
## Getting Started - Linux (Ubuntu)
|
||||
|
||||
Install Packages and Init Repository
|
||||
|
||||
```bash
|
||||
sudo apt install gcc make cmake build-essential g++ nasm clang-format
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
Layout:
|
||||
Compile
|
||||
|
||||
```bash
|
||||
mkdir build && cd build && cmake .. && make -j
|
||||
```
|
||||
|
||||
Run Tests
|
||||
|
||||
```bash
|
||||
./test.sh
|
||||
```
|
||||
|
||||
## Getting Started - Windows
|
||||
|
||||
Install Visual Studio 2019 and get the C++ and CMake tools via the Visual Studio Installer
|
||||
|
||||
On Windows, it's recommended to get Scoop to use as a package manager, making the follow steps _much_ easier. Follow the steps on the bottom of the homepage here https://scoop.sh/
|
||||
|
||||
Once Scoop is installed, run the following command:
|
||||
|
||||
```ps
|
||||
scoop install llvm nasm
|
||||
```
|
||||
|
||||
Initialize the repository's third-party dependencies:
|
||||
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
Open the project as a CMake project, browse for the root level `CMakeLists.txt`:
|
||||
|
||||
![](./doc/imgs/open-cmake-vs.png)
|
||||
|
||||
In the toolbar, you should be able to select an individual component to compile, or combine within the root CMakeLists.txt. In the future we will pre-define configurations to make this easier.
|
||||
|
||||
![](./doc/imgs/cmake-build-vs.png)
|
||||
|
||||
You may also wish to view the files that pertain to each CMake target, rather than the project as it is normally:
|
||||
|
||||
![](./doc/imgs/cmake-target-view.png)
|
||||
|
||||
TODO
|
||||
|
||||
- more steps to follow as we actually figure it out!
|
||||
- running tests
|
||||
- etc
|
||||
|
||||
## Project Layout
|
||||
|
||||
- `goalc` is the GOAL compiler
|
||||
- `gs` contains GOOS code for parts of GOOS implemented in GOOS
|
||||
- `gc` contains GOAL code for parts of GOAL implemented in GOAL (must generate no machine code, just defining macros)
|
||||
|
@ -33,8 +107,10 @@ Layout:
|
|||
- `tests` will contain all tests
|
||||
- `asset_tool` will contain the asset packer/unpacker
|
||||
|
||||
Design:
|
||||
## Design
|
||||
|
||||
(if anybody has better ideas, feel free to suggest improvements! This is just a rough plan for now)
|
||||
|
||||
- All C++ code should build from the top-level `cmake`.
|
||||
- All C++ applications (GOAL compiler, asset extractor, asset packer, runtime, test) should have a script in the top level which launches them.
|
||||
- All file paths should be relative to the `jak` folder.
|
||||
|
@ -52,11 +128,13 @@ Design:
|
|||
- `./gc.sh` : run the compiler in interactive mode
|
||||
- `./gs.sh` : run a goos interpreter in interactive mode
|
||||
- `./decomp.sh : run the decompiler
|
||||
|
||||
Current state:
|
||||
|
||||
## Current State
|
||||
|
||||
- GOAL compiler just implements the GOOS Scheme Macro Language. Running `./gc.sh` just loads the GOOS library (`goalc/gs/goos-lib.gs`) and then goes into an interactive mode. Use `(exit)` to exit.
|
||||
- `./test.sh` runs tests for some game C++ code, for GOOS, for the reader, for the listener connection, and for some early emitter stuff.
|
||||
- The runtime boots in `fakeiso` mode which will load some dummy files. Then the C Kernel (`game/kernel`) will load the `KERNEL.CGO` and `GAME.CGO` files, which are from the "proof of concept" GOAL compiler. If you run `./gk.sh`, you should see it load stuff, then print:
|
||||
- The runtime boots in `fakeiso` mode which will load some dummy files. Then the C Kernel (`game/kernel`) will load the `KERNEL.CGO` and `GAME.CGO` files, which are from the "proof of concept" GOAL compiler. If you run `./gk.sh`, you should see it load stuff, then print:
|
||||
|
||||
```
|
||||
calling play!
|
||||
~~ HACK ~~ : fake play has been called
|
||||
|
@ -65,13 +143,16 @@ InitCheckListener
|
|||
kernel: machine started
|
||||
|
||||
```
|
||||
|
||||
where the `~~ HACK ~~` message is from code in `KERNEL.CGO`.
|
||||
|
||||
Code Guidelines:
|
||||
## Coding Guidelines
|
||||
|
||||
- Avoid warnings
|
||||
- Use asserts over throwing exceptions in game code (throwing exceptions from C code called by GOAL code is sketchy)
|
||||
|
||||
TODOS:
|
||||
## TODOs
|
||||
|
||||
- Build on Windows!
|
||||
- Networking
|
||||
- File paths
|
||||
|
@ -86,8 +167,8 @@ TODOS:
|
|||
- Clean up possible duplicate code in compiler/decompiler `util` folder, consider a common utility library
|
||||
- Clean up header guard names (or just use `#pragma once`?)
|
||||
- Investigate a better config format
|
||||
- The current JSON library seems to have issues with comments, which I really like
|
||||
- Clean up use of namespaces
|
||||
- The current JSON library seems to have issues with comments, which I really like
|
||||
- Clean up use of namespaces
|
||||
- Clean up the print message when `gk` starts.
|
||||
- Finish commenting runtime stuff
|
||||
- Runtime document
|
||||
|
@ -99,11 +180,10 @@ TODOS:
|
|||
- Clean up decompiler print spam, finish up the CFG stuff
|
||||
- Decompiler document
|
||||
|
||||
|
||||
Project Description
|
||||
-----------------------
|
||||
## Project Description
|
||||
|
||||
This project is to port Jak 1 (NTSC, "black label" version) to PC. The strategy is to:
|
||||
|
||||
- recompile for x86 to get much better performance than emulation
|
||||
- create human-reabable GOAL source code that can be modified
|
||||
- create a GOAL compiler for x86-64 which supports live patching of code like the original
|
||||
|
@ -111,6 +191,7 @@ This project is to port Jak 1 (NTSC, "black label" version) to PC. The strategy
|
|||
- unpack assets in a format that can be modified
|
||||
|
||||
There are 6 components to this project
|
||||
|
||||
- GOAL decompiler. The result will be manually cleaned up for running on a PC.
|
||||
- GOAL compiler for x86-64.
|
||||
- Game source code, made from cleaning up the result of the GOAL decompiler.
|
||||
|
@ -119,25 +200,27 @@ There are 6 components to this project
|
|||
- Asset packing tool.
|
||||
|
||||
The process to build the port will be
|
||||
|
||||
- Build data extraction tool, GOAL compiler, and GOAL runtime library (all written in C++)
|
||||
- Run the GOAL compiler on the game source code to build the game engine
|
||||
- Run asset extraction on the game disc to get level data, textures, geometry data, music...
|
||||
- Run the asset packing tool to combine the unpacked assets with the compiled game engine to create the game!
|
||||
|
||||
Some statistics:
|
||||
|
||||
- Estimated ~500k lines of GOAL code
|
||||
- 10410 functions
|
||||
- 5451 functions with no control flow (no branching, loops, if/else, short-circuiting boolean operators, gotos, etc)
|
||||
|
||||
The rough timeline is to finish sometime in 2022. If it looks like this is impossible, the project will be abandoned. But I have already spent about 4 months preparing to start this and seems doable. I also have some background in compilers, and familiarity with PS2 (worked on DobieStation PS2 emulator) / MIPS in general (wrote a PS1 emulator). I think the trick will be making good automated tools - the approach taken for SM64 and other N64 decompilations is way too labor-intensive to work.
|
||||
The rough timeline is to finish sometime in 2022. If it looks like this is impossible, the project will be abandoned. But I have already spent about 4 months preparing to start this and seems doable. I also have some background in compilers, and familiarity with PS2 (worked on DobieStation PS2 emulator) / MIPS in general (wrote a PS1 emulator). I think the trick will be making good automated tools - the approach taken for SM64 and other N64 decompilations is way too labor-intensive to work.
|
||||
|
||||
### GOAL Decompiler
|
||||
|
||||
GOAL Decompiler
|
||||
------------------
|
||||
The decompiler is in progress, at
|
||||
The decompiler is in progress, at
|
||||
https://github.com/water111/jak-disassembler
|
||||
|
||||
Here is the plan for writing the decompiler:
|
||||
|
||||
- [x] Decode the CGO/DGO format.
|
||||
- [x] Decode the linking data format.
|
||||
- [x] Identify all code and disassemble
|
||||
|
@ -151,10 +234,10 @@ Here is the plan for writing the decompiler:
|
|||
- [ ] Variable map and scoping
|
||||
- [ ] S-expression construction (expression stack)
|
||||
|
||||
### GOAL Runtime
|
||||
|
||||
The "runtime" will be a replacement for all of the C/C++ code of the original game. There is C/C++ code that runs on the main processor (EE) and the separate I/O processor (IOP).
|
||||
|
||||
GOAL Runtime
|
||||
--------------
|
||||
The "runtime" will be a replacement for all of the C/C++ code of the original game. There is C/C++ code that runs on the main processor (EE) and the separate I/O processor (IOP).
|
||||
- The "C Kernel", which runs on the EE and contains
|
||||
- [ ] File I/O (for debugging, not used by retail game)
|
||||
- [x] Initialization to boostrap the GOAL Kernel and start the game engine
|
||||
|
@ -184,17 +267,18 @@ The "Sony libraries" are a simple wrapper around my `system` library, which impl
|
|||
|
||||
Likely there will be sound/graphics code in here at some point, but this part is not fully planned yet.
|
||||
|
||||
GOAL Compiler
|
||||
---------------
|
||||
### GOAL Compiler
|
||||
|
||||
The GOAL compiler will target x86-64. At first just Linux. There is a macro language called GOOS which is basically just Scheme but with a few bonus features.
|
||||
|
||||
The compiler will reuse a significant amount of code from my existing LISP compiler for x86-64. I have a very bad WIP combination which is capable of building a modified `gkernel.gc` for x86 as a proof of concept. It can create and run functions in threads.
|
||||
The compiler will reuse a significant amount of code from my existing LISP compiler for x86-64. I have a very bad WIP combination which is capable of building a modified `gkernel.gc` for x86 as a proof of concept. It can create and run functions in threads.
|
||||
|
||||
An important part of the compiler is the test suite. Without tests the compiler will be full of bugs. So every feature should have a good set of tests.
|
||||
An important part of the compiler is the test suite. Without tests the compiler will be full of bugs. So every feature should have a good set of tests.
|
||||
|
||||
The major components are
|
||||
|
||||
- [ ] GOAL-IR, a typed linear intermediate representation for GOAL code
|
||||
|
||||
- [ ] "Environment"
|
||||
- [ ] "Ref"
|
||||
- [ ] Constant propagation of integers/floats
|
||||
|
@ -202,6 +286,7 @@ The major components are
|
|||
- [ ] Ref `in_gpr`
|
||||
|
||||
- [ ] The type system
|
||||
|
||||
- [ ] Type inheritance
|
||||
- [ ] Integer/float/pointer types (value semantics)
|
||||
- [ ] Reference types
|
||||
|
@ -220,41 +305,41 @@ The major components are
|
|||
- [ ] Built-in types in the GOAL runtime/C Kernel
|
||||
|
||||
- [x] The GOOS Macro Language
|
||||
|
||||
- [x] S-expression parser (the "Reader")
|
||||
- [x] Reader text db (for error messages that point to a specific line)
|
||||
- [x] Scheme interpreter
|
||||
|
||||
|
||||
- [ ] Front-end (convert s-expressions (a tree structure) to GOAL-IR (a linear representation))
|
||||
- [ ] Parsing helpers
|
||||
- [ ] Macro expansion
|
||||
- [ ] Control flow/block forms
|
||||
- [ ] Type definitions
|
||||
- [ ] Inline assembly forms
|
||||
- [ ] Function/method call
|
||||
- [ ] Math forms
|
||||
- [ ] Lexical scoping (immediate application of `lambda`)
|
||||
- [ ] Function inlining (slightly different scoping rules of immediate `lambda`)
|
||||
- [ ] Function/macro definition
|
||||
- [ ] Static Objects
|
||||
- [ ] Parsing helpers
|
||||
- [ ] Macro expansion
|
||||
- [ ] Control flow/block forms
|
||||
- [ ] Type definitions
|
||||
- [ ] Inline assembly forms
|
||||
- [ ] Function/method call
|
||||
- [ ] Math forms
|
||||
- [ ] Lexical scoping (immediate application of `lambda`)
|
||||
- [ ] Function inlining (slightly different scoping rules of immediate `lambda`)
|
||||
- [ ] Function/macro definition
|
||||
- [ ] Static Objects
|
||||
|
||||
- [ ] Regsiter allocation
|
||||
- [ ] Analysis
|
||||
- [ ] Allocation
|
||||
- [ ] Stack spilling
|
||||
- [ ] `xmm` and `gpr` promotion/demotions for EE 128-bit register usage
|
||||
|
||||
- [ ] Analysis
|
||||
- [ ] Allocation
|
||||
- [ ] Stack spilling
|
||||
- [ ] `xmm` and `gpr` promotion/demotions for EE 128-bit register usage
|
||||
|
||||
- [ ] Codegen / Emitter (convert GOAL-IR + register allocations to x86 object file format)
|
||||
- [ ] Emitter (convert GOAL-IR to instructions)
|
||||
- [ ] x86-64 instruction generation (actually generate the machine code)
|
||||
- [ ] Linking data
|
||||
- [ ] 64-bit GPR
|
||||
- [ ] 32-bit float
|
||||
- [ ] 128-bit GPR
|
||||
- [ ] 32-bit float x4 vector register
|
||||
- [ ] function prologue/epilogue
|
||||
- [ ] stack spilling
|
||||
- [ ] static object and static object links
|
||||
- [ ] Emitter (convert GOAL-IR to instructions)
|
||||
- [ ] x86-64 instruction generation (actually generate the machine code)
|
||||
- [ ] Linking data
|
||||
- [ ] 64-bit GPR
|
||||
- [ ] 32-bit float
|
||||
- [ ] 128-bit GPR
|
||||
- [ ] 32-bit float x4 vector register
|
||||
- [ ] function prologue/epilogue
|
||||
- [ ] stack spilling
|
||||
- [ ] static object and static object links
|
||||
|
||||
- [ ] Listener/REPL
|
||||
- [ ] Network connection
|
||||
|
@ -264,14 +349,14 @@ The major components are
|
|||
- [ ] Expand single macro debugging feature
|
||||
- [ ] Interface for running gtests
|
||||
|
||||
### Asset Extraction Tool
|
||||
|
||||
Asset Extraction Tool
|
||||
-----------------------
|
||||
Not started yet. The simplest version of this tool is just to use the decompiler logic to turn the level/art-group/texture/TXT files into GOAL source code, and copy all STR/sound/visibility files, as these don't need to be modified.
|
||||
Not started yet. The simplest version of this tool is just to use the decompiler logic to turn the level/art-group/texture/TXT files into GOAL source code, and copy all STR/sound/visibility files, as these don't need to be modified.
|
||||
|
||||
Eventually this should export to a more useful format.
|
||||
|
||||
File formats:
|
||||
|
||||
- [ ] Art group (a GOAL object format)
|
||||
- There may be more formats related to art groups.
|
||||
- [ ] Texture page (a GOAL object format)
|
||||
|
@ -286,12 +371,8 @@ File formats:
|
|||
- [ ] Loading screen image
|
||||
- [ ] save game icon (I do not care about this)
|
||||
|
||||
### Asset Packing Tool
|
||||
|
||||
Asset Packing Tool
|
||||
-----------------------
|
||||
Packs together all assets/compiled code/runtime into a format that can be played. The simplest version to go with the simplest extraction tool will just pass the level/art-group/texture/TXT files to the compiler, and copy STR/sound/visbility files into the fakeiso. Then pack in CGOs/DGOs.
|
||||
Packs together all assets/compiled code/runtime into a format that can be played. The simplest version to go with the simplest extraction tool will just pass the level/art-group/texture/TXT files to the compiler, and copy STR/sound/visbility files into the fakeiso. Then pack in CGOs/DGOs.
|
||||
|
||||
It's important that the asset extraction/packing can be automated so we can avoid distributing the assets, which are large and probably not supposed to be distributed.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "TypeSystem.h"
|
||||
#include "type_util.h"
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
TypeSystem::TypeSystem() {
|
||||
// the "none" and "_type_" types are included by default.
|
||||
|
|
BIN
doc/imgs/cmake-build-vs.png
Normal file
BIN
doc/imgs/cmake-build-vs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
doc/imgs/cmake-target-view.png
Normal file
BIN
doc/imgs/cmake-target-view.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
doc/imgs/open-cmake-vs.png
Normal file
BIN
doc/imgs/open-cmake-vs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -1,11 +1,33 @@
|
|||
# We define our own compilation flags here.
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS "-O0 -ggdb -Wall \
|
||||
-Wextra -Wcast-align -Wcast-qual -Wdisabled-optimization -Wformat=2 \
|
||||
-Winit-self -Wmissing-include-dirs -Woverloaded-virtual \
|
||||
-Wredundant-decls -Wshadow -Wsign-promo ")
|
||||
|
||||
# Set default compile flags for GCC
|
||||
# optimization level can be set here. Note that game/ overwrites this for building game C++ code.
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
message(STATUS "GCC detected, adding compile flags")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
-ggdb \
|
||||
-Wall \
|
||||
-Winit-self \
|
||||
-Wextra \
|
||||
-Wcast-align \
|
||||
-Wcast-qual \
|
||||
-Wdisabled-optimization \
|
||||
-Wformat=2 \
|
||||
-Wmissing-include-dirs \
|
||||
-Woverloaded-virtual \
|
||||
-Wredundant-decls \
|
||||
-Wshadow \
|
||||
-Wsign-promo")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "/EHsc")
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
enable_language(ASM_NASM)
|
||||
set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} asm)
|
||||
set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
|
||||
set_source_files_properties(kernel/asm_funcs.asm PROPERTIES COMPILE_FLAGS "-g")
|
||||
set(RUNTIME_SOURCE
|
||||
runtime.cpp
|
||||
system/SystemThread.cpp
|
||||
|
@ -18,7 +40,7 @@ set(RUNTIME_SOURCE
|
|||
sce/sif_ee.cpp
|
||||
sce/iop.cpp
|
||||
sce/stubs.cpp
|
||||
kernel/asm_funcs.nasm
|
||||
kernel/asm_funcs.asm
|
||||
kernel/fileio.cpp
|
||||
kernel/kboot.cpp
|
||||
kernel/kdgo.cpp
|
||||
|
@ -54,4 +76,11 @@ add_executable(gk ${RUNTIME_SOURCE} main.cpp)
|
|||
# can be used to test other things.
|
||||
add_library(runtime ${RUNTIME_SOURCE})
|
||||
|
||||
target_link_libraries(gk pthread)
|
||||
|
||||
IF (WIN32)
|
||||
# set stuff for windows
|
||||
target_link_libraries(gk mman)
|
||||
ELSE()
|
||||
# set stuff for other systems
|
||||
target_link_libraries(gk pthread)
|
||||
ENDIF()
|
||||
|
|
|
@ -14,8 +14,46 @@ SECTION .TEXT
|
|||
;; a pointer to this array of GOAL arguments as the argument. The reason for this is that GOAL and
|
||||
;; the standard System V ABI used in Linux are different for 8 argument function calls.
|
||||
|
||||
global _format
|
||||
_format:
|
||||
global _format_win32
|
||||
_format_win32:
|
||||
; GOAL will call with regs RDI, RSI, RDX, RCX, R8, R9, R10, R11
|
||||
|
||||
; to make sure the stack frame is aligned
|
||||
sub rsp, 8
|
||||
|
||||
; push all registers and create the register array on the stack
|
||||
push r11
|
||||
push r10
|
||||
push r9
|
||||
push r8
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
|
||||
; set the first argument register to the stack argument array
|
||||
mov rcx, rsp
|
||||
sub rsp, 32
|
||||
|
||||
; call C function to do format, result will go in RAX
|
||||
call format_impl
|
||||
add rsp, 32
|
||||
|
||||
; restore
|
||||
; (note - this could probably just be add rsp 72, we don't care about the value of these register)
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop r8
|
||||
pop r9
|
||||
pop r10
|
||||
pop r11
|
||||
add rsp, 8
|
||||
ret
|
||||
|
||||
global _format_linux
|
||||
_format_linux:
|
||||
; GOAL will call with regs RDI, RSI, RDX, RCX, R8, R9, R10, R11
|
||||
|
||||
; to make sure the stack frame is aligned
|
||||
|
@ -55,8 +93,6 @@ _format:
|
|||
;; run this wrapper to call the real format_impl
|
||||
|
||||
|
||||
|
||||
|
||||
;; The _call_goal_asm function is used to call a GOAL function from C.
|
||||
;; It supports up to 3 arguments and a return value.
|
||||
;; This should be called with the arguments:
|
||||
|
@ -67,9 +103,9 @@ _format:
|
|||
;; - address of the symbol table
|
||||
;; - GOAL memory space offset
|
||||
|
||||
global _call_goal_asm
|
||||
global _call_goal_asm_linux
|
||||
|
||||
_call_goal_asm:
|
||||
_call_goal_asm_linux:
|
||||
;; x86 saved registers we need to modify for GOAL should be saved
|
||||
push r13
|
||||
push r14
|
||||
|
@ -95,4 +131,57 @@ _call_goal_asm:
|
|||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
ret
|
||||
ret
|
||||
|
||||
|
||||
;; The _call_goal_asm function is used to call a GOAL function from C.
|
||||
;; It supports up to 3 arguments and a return value.
|
||||
;; This should be called with the arguments:
|
||||
;; - first goal arg
|
||||
;; - second goal arg
|
||||
;; - third goal arg
|
||||
;; - address of function to call
|
||||
;; - address of the symbol table
|
||||
;; - GOAL memory space offset
|
||||
|
||||
global _call_goal_asm_win32
|
||||
|
||||
_call_goal_asm_win32:
|
||||
push rdx ; 8
|
||||
push rbx ; 16
|
||||
push rbp ; 24
|
||||
push rsi ; 32
|
||||
push rdi ; 40
|
||||
push r8 ; 48
|
||||
push r9 ; 56
|
||||
push r10 ; 64
|
||||
push r11 ; 72
|
||||
push r12 ; 80
|
||||
push r13 ; 88
|
||||
push r14 ; 96
|
||||
push r15 ; 104
|
||||
|
||||
mov rdi, rcx ;; rdi is GOAL first argument, rcx is windows first argument
|
||||
mov rsi, rdx ;; rsi is GOAL second argument, rdx is windows second argument
|
||||
mov rdx, r8 ;; rdx is GOAL third argument, r8 is windows third argument
|
||||
mov r13, r9 ;; r13 is GOAL fp, r9 is windows fourth argument
|
||||
mov r15, [rsp + 144] ;; symbol table
|
||||
mov r14, [rsp + 152] ;; offset
|
||||
|
||||
call r13
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop r11
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbp
|
||||
pop rbx
|
||||
pop rdx
|
||||
|
||||
ret
|
|
@ -4,7 +4,6 @@
|
|||
* DONE!
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include "common/common_types.h"
|
||||
#include "game/sce/libscf.h"
|
||||
|
@ -14,6 +13,13 @@
|
|||
#include "ksocket.h"
|
||||
#include "klisten.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Windows.h"
|
||||
#include <io.h>
|
||||
#elif __linux__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using namespace ee;
|
||||
|
||||
// Level to load on boot
|
||||
|
@ -128,14 +134,21 @@ void KernelCheckAndDispatch() {
|
|||
// dispatch the kernel
|
||||
//(**kernel_dispatcher)();
|
||||
call_goal(Ptr<Function>(kernel_dispatcher->value), 0, 0, 0, s7.offset, g_ee_main_mem);
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
ClearPending();
|
||||
#endif
|
||||
|
||||
// if the listener function changed, it means the kernel ran it, so we should notify compiler.
|
||||
if (MasterDebug && ListenerFunction->value != old_listener) {
|
||||
SendAck();
|
||||
}
|
||||
|
||||
usleep(1000); // todo - remove this
|
||||
#ifdef _WIN32
|
||||
Sleep(1000); // todo - remove this
|
||||
#elif __linux__
|
||||
usleep(1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ void kdsnetm_init_globals() {
|
|||
protoBlock.reset();
|
||||
}
|
||||
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
/*!
|
||||
* Register GOAL DECI2 Protocol Driver with DECI2 service
|
||||
* DONE, EXACT
|
||||
|
@ -219,4 +221,5 @@ s32 SendFromBufferD(s32 msg_kind, u64 p2, char* data, s32 size) {
|
|||
void GoalProtoStatus() {
|
||||
Msg(6, "gproto: got %d %d\n", protoBlock.most_recent_event, protoBlock.most_recent_param);
|
||||
Msg(6, "gproto: %d %d\n", protoBlock.last_receive_size, protoBlock.send_remaining);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -51,6 +51,8 @@ extern GoalProtoBlock protoBlock;
|
|||
*/
|
||||
void kdsnetm_init_globals();
|
||||
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
/*!
|
||||
* Register GOAL DECI2 Protocol Driver with DECI2 service
|
||||
* DONE, EXACT
|
||||
|
@ -63,6 +65,8 @@ void InitGoalProto();
|
|||
*/
|
||||
void ShutdownGoalProto();
|
||||
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Handle a DECI2 Protocol Event for the GOAL Proto.
|
||||
* Called by the DECI2 Protocol driver
|
||||
|
@ -70,6 +74,8 @@ void ShutdownGoalProto();
|
|||
*/
|
||||
void GoalProtoHandler(int event, int param, void* data);
|
||||
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
/*!
|
||||
* Low level DECI2 send
|
||||
* Will block until send is complete.
|
||||
|
@ -77,6 +83,7 @@ void GoalProtoHandler(int event, int param, void* data);
|
|||
* removed
|
||||
*/
|
||||
s32 SendFromBufferD(s32 p1, u64 p2, char* data, s32 size);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Print GOAL Protocol status
|
||||
|
|
|
@ -71,7 +71,10 @@ void ClearPending() {
|
|||
Ptr<char> msg = OutputBufArea.cast<char>() + sizeof(GoalMessageHeader);
|
||||
auto size = strlen(msg.c());
|
||||
// note - if size is ever greater than 2^16 this will cause an issue.
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
SendFromBuffer(msg.c(), size);
|
||||
#endif
|
||||
clear_output();
|
||||
}
|
||||
|
||||
|
@ -84,7 +87,10 @@ void ClearPending() {
|
|||
if (send_size > 64000) {
|
||||
send_size = 64000;
|
||||
}
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
SendFromBufferD(2, 0, msg, send_size);
|
||||
#endif
|
||||
size -= send_size;
|
||||
msg += send_size;
|
||||
}
|
||||
|
@ -103,9 +109,11 @@ void ClearPending() {
|
|||
*/
|
||||
void SendAck() {
|
||||
if (MasterDebug) {
|
||||
#ifdef __linux__
|
||||
SendFromBufferD(u16(ListenerMessageKind::MSG_ACK), protoBlock.msg_id,
|
||||
AckBufArea + sizeof(GoalMessageHeader),
|
||||
strlen(AckBufArea + sizeof(GoalMessageHeader)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -329,7 +329,10 @@ int InitMachine() {
|
|||
// }
|
||||
|
||||
if (MasterDebug) { // connect to GOAL compiler
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
InitGoalProto();
|
||||
#endif
|
||||
}
|
||||
|
||||
printf("InitSound\n");
|
||||
|
@ -359,7 +362,10 @@ int ShutdownMachine() {
|
|||
StopIOP();
|
||||
CloseListener();
|
||||
ShutdownSound();
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
ShutdownGoalProto();
|
||||
#endif
|
||||
Msg(6, "kernel: machine shutdown");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -62,28 +62,59 @@ void output_unload(const char* name);
|
|||
*/
|
||||
void output_segment_load(const char* name, Ptr<u8> link_block, u32 flags);
|
||||
|
||||
#ifdef __linux__
|
||||
/*!
|
||||
* Print to the GOAL print buffer from C
|
||||
*/
|
||||
void cprintf(const char* format, ...) __attribute__((format(printf, 1, 2)));
|
||||
#elif _WIN32
|
||||
/*!
|
||||
* Print to the GOAL print buffer from C
|
||||
*/
|
||||
void cprintf(const char* format, ...);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
/*!
|
||||
* Print directly to the C stdout
|
||||
* The "k" parameter is ignored, so this is just like printf
|
||||
*/
|
||||
void Msg(s32 k, const char* format, ...) __attribute__((format(printf, 2, 3)));
|
||||
#elif _WIN32
|
||||
/*!
|
||||
* Print directly to the C stdout
|
||||
* The "k" parameter is ignored, so this is just like printf
|
||||
*/
|
||||
void Msg(s32 k, const char* format, ...);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
/*!
|
||||
* Print directly to the C stdout
|
||||
* This is identical to Msg.
|
||||
*/
|
||||
void MsgWarn(const char* format, ...) __attribute__((format(printf, 1, 2)));
|
||||
#elif _WIN32
|
||||
/*!
|
||||
* Print directly to the C stdout
|
||||
* This is identical to Msg.
|
||||
*/
|
||||
void MsgWarn(const char* format, ...);
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
/*!
|
||||
* Print directly to the C stdout
|
||||
* This is identical to Msg.
|
||||
*/
|
||||
void MsgErr(const char* format, ...) __attribute__((format(printf, 1, 2)));
|
||||
#elif _WIN32
|
||||
/*!
|
||||
* Print directly to the C stdout
|
||||
* This is identical to Msg.
|
||||
*/
|
||||
void MsgErr(const char* format, ...);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Reverse string in place.
|
||||
|
|
|
@ -313,13 +313,7 @@ u64 make_string_from_c(const char* c_str) {
|
|||
return mem;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create a GOAL function from a C function. This doesn't export it as a global function, it just
|
||||
* creates a function object on the global heap.
|
||||
*
|
||||
* The implementation is to create a simple trampoline function which jumps to the C function.
|
||||
*/
|
||||
Ptr<Function> make_function_from_c(void* func) {
|
||||
Ptr<Function> make_function_from_c_linux(void* func) {
|
||||
// allocate a function object on the global heap
|
||||
auto mem = Ptr<u8>(
|
||||
alloc_heap_object(s7.offset + FIX_SYM_GLOBAL_HEAP, *(s7 + FIX_SYM_FUNCTION_TYPE), 0x40));
|
||||
|
@ -344,6 +338,68 @@ Ptr<Function> make_function_from_c(void* func) {
|
|||
return mem.cast<Function>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create a GOAL function from a C function. This doesn't export it as a global function, it just
|
||||
* creates a function object on the global heap.
|
||||
*
|
||||
* The implementation is to create a simple trampoline function which jumps to the C function.
|
||||
*/
|
||||
Ptr<Function> make_function_from_c_win32(void* func) {
|
||||
// allocate a function object on the global heap
|
||||
auto mem = Ptr<u8>(
|
||||
alloc_heap_object(s7.offset + FIX_SYM_GLOBAL_HEAP, *(s7 + FIX_SYM_FUNCTION_TYPE), 0x80));
|
||||
auto f = (uint64_t)func;
|
||||
auto fp = (u8*)&f;
|
||||
|
||||
int i = 0;
|
||||
// we will put the function address in RAX with a movabs rax, imm8
|
||||
mem.c()[i++] = 0x48;
|
||||
mem.c()[i++] = 0xb8;
|
||||
for (int j = 0; j < 8; j++) {
|
||||
mem.c()[i++] = fp[j];
|
||||
}
|
||||
|
||||
/*
|
||||
* push rdi
|
||||
* push rsi
|
||||
* push rdx
|
||||
* push rcx
|
||||
* pop r9
|
||||
* pop r8
|
||||
* pop rdx
|
||||
* pop rcx
|
||||
*
|
||||
* sub rsp, 40
|
||||
* call rax
|
||||
* add rsp, 40
|
||||
* ret
|
||||
*/
|
||||
for (auto x : {0x57, 0x56, 0x52, 0x51, 0x41, 0x59, 0x41, 0x58, 0x5A, 0x59, 0x48,
|
||||
0x83, 0xEC, 0x28, 0xFF, 0xD0, 0x48, 0x83, 0xC4, 0x28, 0xC3}) {
|
||||
mem.c()[i++] = x;
|
||||
}
|
||||
|
||||
// the C function's ret will return to the caller of this trampoline.
|
||||
|
||||
// CacheFlush(mem, 0x34);
|
||||
|
||||
return mem.cast<Function>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create a GOAL function from a C function. This doesn't export it as a global function, it just
|
||||
* creates a function object on the global heap.
|
||||
*
|
||||
* The implementation is to create a simple trampoline function which jumps to the C function.
|
||||
*/
|
||||
Ptr<Function> make_function_from_c(void* func) {
|
||||
#ifdef __linux__
|
||||
return make_function_from_c_linux(func);
|
||||
#elif _WIN32
|
||||
return make_function_from_c_win32(func);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create a GOAL function which does nothing and immediately returns.
|
||||
*/
|
||||
|
@ -890,8 +946,12 @@ u64 method_set(u32 type_, u32 method_id, u32 method) {
|
|||
}
|
||||
|
||||
extern "C" {
|
||||
// defined in asm_funcs.nasm
|
||||
uint64_t _call_goal_asm(u64 a0, u64 a1, u64 a2, void* fptr, void* st_ptr, void* offset);
|
||||
// defined in asm_funcs.asm
|
||||
#ifdef __linux__
|
||||
uint64_t _call_goal_asm_linux(u64 a0, u64 a1, u64 a2, void* fptr, void* st_ptr, void* offset);
|
||||
#elif _WIN32
|
||||
uint64_t _call_goal_asm_win32(u64 a0, u64 a1, u64 a2, void* fptr, void* st_ptr, void* offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -900,7 +960,11 @@ uint64_t _call_goal_asm(u64 a0, u64 a1, u64 a2, void* fptr, void* st_ptr, void*
|
|||
u64 call_goal(Ptr<Function> f, u64 a, u64 b, u64 c, u64 st, void* offset) {
|
||||
auto st_ptr = (void*)((uint8_t*)(offset) + st);
|
||||
void* fptr = f.c();
|
||||
return _call_goal_asm(a, b, c, fptr, st_ptr, offset);
|
||||
#ifdef __linux__
|
||||
return _call_goal_asm_linux(a, b, c, fptr, st_ptr, offset);
|
||||
#elif _WIN32
|
||||
return _call_goal_asm_win32(a, b, c, fptr, st_ptr, offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1453,7 +1517,11 @@ s32 test_function(s32 arg0, s32 arg1, s32 arg2, s32 arg3) {
|
|||
|
||||
extern "C" {
|
||||
// defined in asm_funcs. It calls format_impl and sets up arguments correctly.
|
||||
void _format();
|
||||
#ifdef __linux__
|
||||
void _format_linux();
|
||||
#elif _WIN32
|
||||
void _format_win32();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1705,8 +1773,11 @@ s32 InitHeapAndSymbol() {
|
|||
make_function_symbol_from_c("load", (void*)load);
|
||||
make_function_symbol_from_c("loado", (void*)loado);
|
||||
make_function_symbol_from_c("unload", (void*)unload);
|
||||
|
||||
make_function_symbol_from_c("_format", (void*)_format);
|
||||
#ifdef __linux__
|
||||
make_function_symbol_from_c("_format", (void*)_format_linux);
|
||||
#elif _WIN32
|
||||
make_function_symbol_from_c("_format", (void*)_format_win32);
|
||||
#endif
|
||||
|
||||
// allocations
|
||||
make_function_symbol_from_c("malloc", (void*)alloc_heap_memory);
|
||||
|
@ -1885,4 +1956,4 @@ s64 load_and_link(const char* filename, char* decode_name, kheapinfo* heap, u32
|
|||
return (s32)rv.offset;
|
||||
}
|
||||
|
||||
// todo, read lcock code
|
||||
// todo, read lcock code
|
||||
|
|
|
@ -52,6 +52,8 @@ u32 ReceiveToBuffer(char* buff) {
|
|||
return msg_size;
|
||||
}
|
||||
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
/*!
|
||||
* Do a DECI2 send and block until it is complete.
|
||||
* The message type is OUTPUT
|
||||
|
@ -60,6 +62,7 @@ u32 ReceiveToBuffer(char* buff) {
|
|||
s32 SendFromBuffer(char* buff, s32 size) {
|
||||
return SendFromBufferD(u16(ListenerMessageKind::MSG_OUTPUT), 0, buff, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Just prepare the Ack buffer, doesn't actually connect.
|
||||
|
|
|
@ -73,6 +73,7 @@ void fake_iso_init_globals() {
|
|||
|
||||
//! will hold prefix for the source folder.
|
||||
static const char* next_dir = nullptr;
|
||||
static const char* fake_iso_path = nullptr;
|
||||
|
||||
/*!
|
||||
* Initialize the file system.
|
||||
|
@ -80,13 +81,15 @@ 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");
|
||||
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?
|
||||
fake_iso_path = std::getenv("FAKE_ISO_PATH");
|
||||
assert(fake_iso_path);
|
||||
strcat(fakeiso_path, fake_iso_path);
|
||||
|
||||
// open the map.
|
||||
FILE* fp = fopen(fakeiso_path, "r");
|
||||
|
@ -191,7 +194,9 @@ static const char* get_file_path(FileRecord* fr) {
|
|||
assert(fr->location < fake_iso_entry_count);
|
||||
static char path_buffer[1024];
|
||||
strcpy(path_buffer, next_dir);
|
||||
#ifdef __linux__
|
||||
strcat(path_buffer, "/");
|
||||
#endif
|
||||
strcat(path_buffer, fake_iso_entries[fr->location].file_path);
|
||||
return path_buffer;
|
||||
}
|
||||
|
@ -350,4 +355,4 @@ uint32_t FS_LoadSoundBank(char* name, void* buffer) {
|
|||
(void)name;
|
||||
(void)buffer;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,15 @@
|
|||
* Setup and launcher for the runtime.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#elif _WIN32
|
||||
#include <io.h>
|
||||
#include <third-party/mman/mman.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "runtime.h"
|
||||
|
@ -38,21 +45,29 @@
|
|||
|
||||
u8* g_ee_main_mem = nullptr;
|
||||
|
||||
/*!
|
||||
* TODO-WINDOWS
|
||||
* runtime.cpp - Deci2Listener has been disabled for now, pending rewriting for Windows.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
/*!
|
||||
* SystemThread function for running the DECI2 communication with the GOAL compiler.
|
||||
*/
|
||||
void deci2_runner(SystemThreadInterface& interface) {
|
||||
|
||||
void deci2_runner(SystemThreadInterface& iface) {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
// callback function so the server knows when to give up and shutdown
|
||||
std::function<bool()> shutdown_callback = [&]() { return interface.get_want_exit(); };
|
||||
std::function<bool()> shutdown_callback = [&]() { return iface.get_want_exit(); };
|
||||
|
||||
// create and register server
|
||||
Deci2Server server(shutdown_callback);
|
||||
ee::LIBRARY_sceDeci2_register(&server);
|
||||
|
||||
// now its ok to continue with initialization
|
||||
interface.initialization_complete();
|
||||
iface.initialization_complete();
|
||||
|
||||
// in our own thread, wait for the EE to register the first protocol driver
|
||||
printf("[DECI2] waiting for EE to register protos\n");
|
||||
|
@ -64,7 +79,7 @@ void deci2_runner(SystemThreadInterface& interface) {
|
|||
|
||||
printf("[DECI2] waiting for listener...\n");
|
||||
bool saw_listener = false;
|
||||
while (!interface.get_want_exit()) {
|
||||
while (!iface.get_want_exit()) {
|
||||
if (server.check_for_listener()) {
|
||||
if (!saw_listener) {
|
||||
printf("[DECI2] Connected!\n");
|
||||
|
@ -77,6 +92,7 @@ void deci2_runner(SystemThreadInterface& interface) {
|
|||
usleep(50000);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// EE System
|
||||
|
@ -95,7 +111,7 @@ constexpr int GOAL_ARGC = 4;
|
|||
/*!
|
||||
* SystemThread Function for the EE (PS2 Main CPU)
|
||||
*/
|
||||
void ee_runner(SystemThreadInterface& interface) {
|
||||
void ee_runner(SystemThreadInterface& iface) {
|
||||
// Allocate Main RAM. Must have execute enabled.
|
||||
if (EE_MEM_LOW_MAP) {
|
||||
g_ee_main_mem =
|
||||
|
@ -109,7 +125,7 @@ void ee_runner(SystemThreadInterface& interface) {
|
|||
|
||||
if (g_ee_main_mem == (u8*)(-1)) {
|
||||
printf(" Failed to initialize main memory! %s\n", strerror(errno));
|
||||
interface.initialization_complete();
|
||||
iface.initialization_complete();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -118,7 +134,7 @@ void ee_runner(SystemThreadInterface& interface) {
|
|||
(double)EE_MAIN_MEM_SIZE / (1 << 20));
|
||||
|
||||
printf("[EE] Initialization complete!\n");
|
||||
interface.initialization_complete();
|
||||
iface.initialization_complete();
|
||||
|
||||
printf("[EE] Run!\n");
|
||||
memset((void*)g_ee_main_mem, 0, EE_MAIN_MEM_SIZE);
|
||||
|
@ -145,13 +161,13 @@ void ee_runner(SystemThreadInterface& interface) {
|
|||
munmap(g_ee_main_mem, EE_MAIN_MEM_SIZE);
|
||||
|
||||
// after main returns, trigger a shutdown.
|
||||
interface.trigger_shutdown();
|
||||
iface.trigger_shutdown();
|
||||
}
|
||||
|
||||
/*!
|
||||
* SystemThread function for running the IOP (separate I/O Processor)
|
||||
*/
|
||||
void iop_runner(SystemThreadInterface& interface) {
|
||||
void iop_runner(SystemThreadInterface& iface) {
|
||||
IOP iop;
|
||||
printf("\n\n\n[IOP] Restart!\n");
|
||||
iop.reset_allocator();
|
||||
|
@ -174,7 +190,7 @@ void iop_runner(SystemThreadInterface& interface) {
|
|||
// ssound
|
||||
// stream
|
||||
|
||||
interface.initialization_complete();
|
||||
iface.initialization_complete();
|
||||
|
||||
printf("[IOP] Wait for OVERLORD to be started...\n");
|
||||
iop.wait_for_overlord_start_cmd();
|
||||
|
@ -195,7 +211,7 @@ void iop_runner(SystemThreadInterface& interface) {
|
|||
iop.signal_overlord_init_finish();
|
||||
|
||||
// IOP Kernel loop
|
||||
while (!interface.get_want_exit() && !iop.want_exit) {
|
||||
while (!iface.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. Each time the EE is waiting on the IOP, it will run an iteration of the IOP kernel.
|
||||
iop.wait_run_iop();
|
||||
|
@ -220,7 +236,10 @@ void exec_runtime(int argc, char** argv) {
|
|||
// step 1: sce library prep
|
||||
iop::LIBRARY_INIT();
|
||||
ee::LIBRARY_INIT_sceCd();
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
ee::LIBRARY_INIT_sceDeci2();
|
||||
#endif
|
||||
ee::LIBRARY_INIT_sceSif();
|
||||
|
||||
// step 2: system prep
|
||||
|
@ -244,4 +263,4 @@ void exec_runtime(int argc, char** argv) {
|
|||
// join and exit
|
||||
tm.join();
|
||||
printf("GOAL Runtime Shutdown\n");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,17 +12,23 @@
|
|||
namespace ee {
|
||||
|
||||
namespace {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
constexpr int MAX_DECI2_PROTOCOLS = 4;
|
||||
Deci2Driver protocols[MAX_DECI2_PROTOCOLS]; // info for each deci2 protocol registered
|
||||
int protocol_count; // number of registered protocols
|
||||
Deci2Driver* sending_driver; // currently sending protocol driver
|
||||
::Deci2Server* server; // the server to send data to
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
/*!
|
||||
/*
|
||||
* Initialize the library.
|
||||
*/
|
||||
void LIBRARY_INIT_sceDeci2() {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
// reset protocols
|
||||
for (auto& p : protocols) {
|
||||
p = Deci2Driver();
|
||||
|
@ -30,12 +36,15 @@ void LIBRARY_INIT_sceDeci2() {
|
|||
protocol_count = 0;
|
||||
server = nullptr;
|
||||
sending_driver = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Run any pending requested sends.
|
||||
*/
|
||||
void LIBRARY_sceDeci2_run_sends() {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
for (auto& prot : protocols) {
|
||||
if (prot.active && prot.pending_send == 'H') {
|
||||
sending_driver = &prot;
|
||||
|
@ -45,13 +54,17 @@ void LIBRARY_sceDeci2_run_sends() {
|
|||
(prot.handler)(DECI2_WRITEDONE, 0, prot.opt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Register a Deci2Server with this library.
|
||||
*/
|
||||
void LIBRARY_sceDeci2_register(::Deci2Server* s) {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
server = s;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -60,6 +73,8 @@ void LIBRARY_sceDeci2_register(::Deci2Server* s) {
|
|||
* I don't know why it's like this.
|
||||
*/
|
||||
s32 sceDeci2Open(u16 protocol, void* opt, void (*handler)(s32 event, s32 param, void* opt)) {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
server->lock();
|
||||
Deci2Driver drv;
|
||||
drv.protocol = protocol;
|
||||
|
@ -78,14 +93,20 @@ s32 sceDeci2Open(u16 protocol, void* opt, void (*handler)(s32 event, s32 param,
|
|||
}
|
||||
|
||||
return drv.id;
|
||||
#elif _WIN32
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Deactivate a DECI2 protocol by socket descriptor.
|
||||
*/
|
||||
s32 sceDeci2Close(s32 s) {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
assert(s - 1 < protocol_count);
|
||||
protocols[s - 1].active = false;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -93,9 +114,12 @@ s32 sceDeci2Close(s32 s) {
|
|||
* Start a send.
|
||||
*/
|
||||
s32 sceDeci2ReqSend(s32 s, char dest) {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
assert(s - 1 < protocol_count);
|
||||
auto& proto = protocols[s - 1];
|
||||
proto.pending_send = dest;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -104,6 +128,8 @@ s32 sceDeci2ReqSend(s32 s, char dest) {
|
|||
* Returns after data is copied.
|
||||
*/
|
||||
s32 sceDeci2ExRecv(s32 s, void* buf, u16 len) {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
assert(s - 1 < protocol_count);
|
||||
protocols[s - 1].recv_size = len;
|
||||
auto avail = protocols[s - 1].available_to_receive;
|
||||
|
@ -114,12 +140,17 @@ s32 sceDeci2ExRecv(s32 s, void* buf, u16 len) {
|
|||
printf("[DECI2] Error: ExRecv %d, only %d available!\n", len, avail);
|
||||
return -1;
|
||||
}
|
||||
#elif _WIN32
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Do a send.
|
||||
*/
|
||||
s32 sceDeci2ExSend(s32 s, void* buf, u16 len) {
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
assert(s - 1 < protocol_count);
|
||||
if (!sending_driver) {
|
||||
printf("sceDeci2ExSend called at illegal time!\n");
|
||||
|
@ -131,6 +162,8 @@ s32 sceDeci2ExSend(s32 s, void* buf, u16 len) {
|
|||
|
||||
server->send_data(buf, len);
|
||||
return len;
|
||||
#elif _WIN32
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace ee
|
||||
} // namespace ee
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
* Works with deci2.cpp (sceDeci2) to implement the networking on target
|
||||
*/
|
||||
|
||||
// TODO-WINDOWS
|
||||
#ifdef __linux__
|
||||
|
||||
#include <cstdio>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
@ -262,3 +265,4 @@ void Deci2Server::accept_thread_func() {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
* Works with deci2.cpp (sceDeci2) to implement the networking on target
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#ifndef JAK1_DECI2SERVER_H
|
||||
#define JAK1_DECI2SERVER_H
|
||||
|
||||
|
@ -51,3 +52,4 @@ class Deci2Server {
|
|||
};
|
||||
|
||||
#endif // JAK1_DECI2SERVER_H
|
||||
#endif
|
||||
|
|
|
@ -83,7 +83,7 @@ void* bootstrap_thread_func(void* x) {
|
|||
void SystemThread::start(std::function<void(SystemThreadInterface&)> f) {
|
||||
printf("# Initialize %s...\n", name.c_str());
|
||||
function = f;
|
||||
pthread_create(&thread, nullptr, bootstrap_thread_func, this);
|
||||
thread = std::thread(bootstrap_thread_func, this);
|
||||
running = true;
|
||||
|
||||
// and wait for initialization
|
||||
|
@ -99,8 +99,7 @@ void SystemThread::start(std::function<void(SystemThreadInterface&)> f) {
|
|||
* Join a system thread
|
||||
*/
|
||||
void SystemThread::join() {
|
||||
void* x;
|
||||
pthread_join(thread, &x);
|
||||
thread.join();
|
||||
running = false;
|
||||
}
|
||||
|
||||
|
@ -136,6 +135,8 @@ void SystemThreadInterface::trigger_shutdown() {
|
|||
thread.manager->shutdown();
|
||||
}
|
||||
|
||||
// TODO-Windows
|
||||
#ifdef __linux__
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
|
@ -164,4 +165,5 @@ void SystemThreadInterface::report_perf_stats() {
|
|||
thread.last_cpu_user = current_user;
|
||||
thread.last_collection_nanoseconds = current_ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -8,10 +8,11 @@
|
|||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <pthread.h>
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
constexpr int MAX_SYSTEM_THREADS = 16;
|
||||
|
@ -39,7 +40,7 @@ class SystemThread {
|
|||
friend void* bootstrap_thread_func(void* thd);
|
||||
|
||||
std::string name = "invalid";
|
||||
pthread_t thread;
|
||||
std::thread thread;
|
||||
SystemThreadManager* manager;
|
||||
std::function<void(SystemThreadInterface&)> function;
|
||||
bool initialization_complete = false;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef JAK_DECIM_COMMON_H
|
||||
#define JAK_DECIM_COMMON_H
|
||||
#include "common/common_types.h"
|
||||
|
||||
struct Deci2Driver {
|
||||
u16 protocol = 0;
|
||||
void* opt = nullptr;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include "iop_thread.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#elif _WIN32
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include "SystemThread.h"
|
||||
//#include "shared_config.h"
|
||||
//#include "ps2/SCE_IOP.h"
|
||||
|
|
1
gc.sh
1
gc.sh
|
@ -4,4 +4,5 @@
|
|||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
export NEXT_DIR=$DIR
|
||||
export FAKE_ISO_PATH=/game/fake_iso.txt
|
||||
$DIR/build/goalc/goalc "$@"
|
1
gk.sh
1
gk.sh
|
@ -4,4 +4,5 @@
|
|||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
export NEXT_DIR=$DIR
|
||||
export FAKE_ISO_PATH=/game/fake_iso.txt
|
||||
$DIR/build/game/gk "$@"
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
add_subdirectory(util)
|
||||
add_subdirectory(goos)
|
||||
add_subdirectory(listener)
|
||||
IF (WIN32)
|
||||
# TODO - implement windows listener
|
||||
message("Windows Listener Not Implemented!")
|
||||
ELSE()
|
||||
add_subdirectory(listener)
|
||||
ENDIF()
|
||||
add_subdirectory(emitter)
|
||||
|
||||
add_executable(goalc main.cpp
|
||||
compiler/Compiler.cpp)
|
||||
|
||||
IF (WIN32)
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
ENDIF()
|
||||
|
||||
target_link_libraries(goalc util goos type_system)
|
|
@ -6,7 +6,13 @@
|
|||
* The CodeTester can't be used for tests requiring the full GOAL language/linking.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/mman.h>
|
||||
#elif _WIN32
|
||||
#include <third-party/mman/mman.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include "CodeTester.h"
|
||||
#include "IGen.h"
|
||||
|
||||
|
|
|
@ -925,4 +925,4 @@ Object Interpreter::eval_while(const Object& form,
|
|||
return rv;
|
||||
}
|
||||
|
||||
} // namespace goos
|
||||
} // namespace goos
|
||||
|
|
|
@ -652,13 +652,13 @@ bool Reader::try_token_as_integer(const Token& tok, Object& obj) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t v = 0;
|
||||
try {
|
||||
std::size_t end = 0;
|
||||
v = std::stoll(tok.text, &end);
|
||||
if (end != tok.text.size())
|
||||
if (end != tok.text.size()) {
|
||||
return false;
|
||||
}
|
||||
obj = Object::make_integer(v);
|
||||
return true;
|
||||
} catch (std::exception& e) {
|
||||
|
@ -707,4 +707,4 @@ void Reader::throw_reader_error(TextStream& here, const std::string& err, int se
|
|||
std::string Reader::get_source_dir() {
|
||||
return source_dir;
|
||||
}
|
||||
} // namespace goos
|
||||
} // namespace goos
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
* The Listener can connect to a Deci2Server for debugging.
|
||||
*/
|
||||
|
||||
// TODO-Windows
|
||||
#ifdef __linux__
|
||||
|
||||
#include <stdexcept>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -239,3 +242,4 @@ void Listener::receive_func() {
|
|||
}
|
||||
|
||||
} // namespace listener
|
||||
#endif
|
||||
|
|
1
test.sh
1
test.sh
|
@ -4,4 +4,5 @@
|
|||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
export NEXT_DIR=$DIR
|
||||
export FAKE_ISO_PATH=/game/fake_iso.txt
|
||||
$DIR/build/test/goalc-test --gtest_color=yes "$@"
|
|
@ -1,3 +1,5 @@
|
|||
enable_testing()
|
||||
|
||||
add_executable(goalc-test
|
||||
test_main.cpp
|
||||
test_test.cpp
|
||||
|
@ -14,4 +16,11 @@ add_executable(goalc-test
|
|||
test_emitter_integer_math.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(goalc-test goos util listener runtime emitter type_system gtest)
|
||||
IF (WIN32)
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
# TODO - implement windows listener
|
||||
message("Windows Listener Not Implemented!")
|
||||
target_link_libraries(goalc-test mman goos util runtime emitter type_system gtest)
|
||||
ELSE()
|
||||
target_link_libraries(goalc-test goos util listener runtime emitter type_system gtest)
|
||||
ENDIF()
|
||||
|
|
|
@ -946,6 +946,8 @@ TEST(GoosObject, char_to_string) {
|
|||
* Test the EmptyListObject
|
||||
*/
|
||||
TEST(GoosObject, EmptyList) {
|
||||
// TODO-Windows
|
||||
#ifdef __linux__
|
||||
// create two empty lists
|
||||
Object nil = EmptyListObject::make_new();
|
||||
Object nil2 = EmptyListObject::make_new();
|
||||
|
@ -965,6 +967,7 @@ TEST(GoosObject, EmptyList) {
|
|||
// check print and inspect
|
||||
EXPECT_EQ(nil.print(), "()");
|
||||
EXPECT_EQ(nil.inspect(), "[empty list] ()\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1286,4 +1289,4 @@ TEST(GoosSpecialForms, And) {
|
|||
for (auto x : {"(and)"}) {
|
||||
EXPECT_ANY_THROW(e(i, x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,7 +157,8 @@ TEST(Kernel, ftoa) {
|
|||
ftoa(buffer, 1., 1, ' ', 1, 0);
|
||||
EXPECT_EQ("1.0", std::string(buffer));
|
||||
|
||||
ftoa(buffer, 0.f / 0.f, 1, ' ', 4, 0);
|
||||
float zero = 0.0f;
|
||||
ftoa(buffer, 0.f / zero, 1, ' ', 4, 0);
|
||||
EXPECT_EQ("NaN", std::string(buffer));
|
||||
|
||||
ftoa(buffer, 1., 8, ' ', 1, 0);
|
||||
|
@ -166,7 +167,7 @@ TEST(Kernel, ftoa) {
|
|||
ftoa(buffer, -1., 8, '0', 1, 0);
|
||||
EXPECT_EQ("0000-1.0", std::string(buffer));
|
||||
|
||||
ftoa(buffer, 0.f / 0.f, 8, ' ', 4, 0);
|
||||
ftoa(buffer, 0.f / zero, 8, ' ', 4, 0);
|
||||
EXPECT_EQ(" NaN", std::string(buffer));
|
||||
|
||||
ftoa(buffer, 0.1, 1, ' ', 4, 0);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#ifdef __linux__
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "goalc/listener/Listener.h"
|
||||
#include "game/system/Deci2Server.h"
|
||||
|
@ -123,4 +125,6 @@ TEST(Listener, ListenerMultipleDecis) {
|
|||
}
|
||||
l.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
1
third-party/mman/CMakeLists.txt
vendored
Normal file
1
third-party/mman/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
add_library(mman SHARED mman.c)
|
180
third-party/mman/mman.c
vendored
Normal file
180
third-party/mman/mman.c
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "mman.h"
|
||||
|
||||
#ifndef FILE_MAP_EXECUTE
|
||||
#define FILE_MAP_EXECUTE 0x0020
|
||||
#endif /* FILE_MAP_EXECUTE */
|
||||
|
||||
static int __map_mman_error(const DWORD err, const int deferr)
|
||||
{
|
||||
if (err == 0)
|
||||
return 0;
|
||||
//TODO: implement
|
||||
return err;
|
||||
}
|
||||
|
||||
static DWORD __map_mmap_prot_page(const int prot)
|
||||
{
|
||||
DWORD protect = 0;
|
||||
|
||||
if (prot == PROT_NONE)
|
||||
return protect;
|
||||
|
||||
if ((prot & PROT_EXEC) != 0)
|
||||
{
|
||||
protect = ((prot & PROT_WRITE) != 0) ?
|
||||
PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
protect = ((prot & PROT_WRITE) != 0) ?
|
||||
PAGE_READWRITE : PAGE_READONLY;
|
||||
}
|
||||
|
||||
return protect;
|
||||
}
|
||||
|
||||
static DWORD __map_mmap_prot_file(const int prot)
|
||||
{
|
||||
DWORD desiredAccess = 0;
|
||||
|
||||
if (prot == PROT_NONE)
|
||||
return desiredAccess;
|
||||
|
||||
if ((prot & PROT_READ) != 0)
|
||||
desiredAccess |= FILE_MAP_READ;
|
||||
if ((prot & PROT_WRITE) != 0)
|
||||
desiredAccess |= FILE_MAP_WRITE;
|
||||
if ((prot & PROT_EXEC) != 0)
|
||||
desiredAccess |= FILE_MAP_EXECUTE;
|
||||
|
||||
return desiredAccess;
|
||||
}
|
||||
|
||||
void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
|
||||
{
|
||||
HANDLE fm, h;
|
||||
|
||||
void * map = MAP_FAILED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4293)
|
||||
#endif
|
||||
|
||||
const DWORD dwFileOffsetLow = (sizeof(off_t) <= sizeof(DWORD)) ?
|
||||
(DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
|
||||
const DWORD dwFileOffsetHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
|
||||
(DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
|
||||
const DWORD protect = __map_mmap_prot_page(prot);
|
||||
const DWORD desiredAccess = __map_mmap_prot_file(prot);
|
||||
|
||||
const off_t maxSize = off + (off_t)len;
|
||||
|
||||
const DWORD dwMaxSizeLow = (sizeof(off_t) <= sizeof(DWORD)) ?
|
||||
(DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL);
|
||||
const DWORD dwMaxSizeHigh = (sizeof(off_t) <= sizeof(DWORD)) ?
|
||||
(DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
errno = 0;
|
||||
|
||||
if (len == 0
|
||||
/* Unsupported flag combinations */
|
||||
|| (flags & MAP_FIXED) != 0
|
||||
/* Usupported protection combinations */
|
||||
|| prot == PROT_EXEC)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
h = ((flags & MAP_ANONYMOUS) == 0) ?
|
||||
(HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE;
|
||||
|
||||
if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = EBADF;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL);
|
||||
|
||||
if (fm == NULL)
|
||||
{
|
||||
errno = __map_mman_error(GetLastError(), EPERM);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len);
|
||||
|
||||
CloseHandle(fm);
|
||||
|
||||
if (map == NULL)
|
||||
{
|
||||
errno = __map_mman_error(GetLastError(), EPERM);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
int munmap(void *addr, size_t len)
|
||||
{
|
||||
if (UnmapViewOfFile(addr))
|
||||
return 0;
|
||||
|
||||
errno = __map_mman_error(GetLastError(), EPERM);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mprotect(void *addr, size_t len, int prot)
|
||||
{
|
||||
DWORD newProtect = __map_mmap_prot_page(prot);
|
||||
DWORD oldProtect = 0;
|
||||
|
||||
if (VirtualProtect(addr, len, newProtect, &oldProtect))
|
||||
return 0;
|
||||
|
||||
errno = __map_mman_error(GetLastError(), EPERM);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int msync(void *addr, size_t len, int flags)
|
||||
{
|
||||
if (FlushViewOfFile(addr, len))
|
||||
return 0;
|
||||
|
||||
errno = __map_mman_error(GetLastError(), EPERM);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mlock(const void *addr, size_t len)
|
||||
{
|
||||
if (VirtualLock((LPVOID)addr, len))
|
||||
return 0;
|
||||
|
||||
errno = __map_mman_error(GetLastError(), EPERM);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int munlock(const void *addr, size_t len)
|
||||
{
|
||||
if (VirtualUnlock((LPVOID)addr, len))
|
||||
return 0;
|
||||
|
||||
errno = __map_mman_error(GetLastError(), EPERM);
|
||||
|
||||
return -1;
|
||||
}
|
57
third-party/mman/mman.h
vendored
Normal file
57
third-party/mman/mman.h
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* sys/mman.h
|
||||
* mman-win32
|
||||
*/
|
||||
|
||||
#ifndef _SYS_MMAN_H_
|
||||
#define _SYS_MMAN_H_
|
||||
|
||||
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
|
||||
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
|
||||
#endif
|
||||
|
||||
/* All the headers include this file. */
|
||||
#ifndef _MSC_VER
|
||||
#include <_mingw.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define PROT_NONE 0
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define PROT_EXEC 4
|
||||
|
||||
#define MAP_FILE 0
|
||||
#define MAP_SHARED 1
|
||||
#define MAP_PRIVATE 2
|
||||
#define MAP_POPULATE 0x08000
|
||||
#define MAP_TYPE 0xf
|
||||
#define MAP_FIXED 0x10
|
||||
#define MAP_ANONYMOUS 0x20
|
||||
#define MAP_32BIT 0x40 /* Only give out 32-bit addresses. */
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
|
||||
#define MAP_FAILED ((void *)-1)
|
||||
|
||||
/* Flags for msync. */
|
||||
#define MS_ASYNC 1
|
||||
#define MS_SYNC 2
|
||||
#define MS_INVALIDATE 4
|
||||
|
||||
void* mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
|
||||
int munmap(void *addr, size_t len);
|
||||
int mprotect(void *addr, size_t len, int prot);
|
||||
int msync(void *addr, size_t len, int flags);
|
||||
int mlock(const void *addr, size_t len);
|
||||
int munlock(const void *addr, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_MMAN_H_ */
|
Loading…
Reference in a new issue