mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 00:57:44 -04:00
Add the STR RPC to overlord and game code (#134)
* work in progress streaming rpc, simple test is working * actually add the test * debug windows failure * windows fix maybe * windows 2 * use str-load-status * update types
This commit is contained in:
parent
460ec874bb
commit
19b8bb81c9
|
@ -307,4 +307,12 @@ void MakeISOName(char* dst, const char* src) {
|
|||
}
|
||||
*dst_ptr = 0;
|
||||
}
|
||||
|
||||
void assert_file_exists(const char* path, const char* error_message) {
|
||||
if (!std::filesystem::exists(path)) {
|
||||
fprintf(stderr, "File %s was not found: %s\n", path, error_message);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace file_util
|
||||
|
|
|
@ -25,4 +25,5 @@ uint32_t crc32(const uint8_t* data, size_t size);
|
|||
uint32_t crc32(const std::vector<uint8_t>& data);
|
||||
void MakeISOName(char* dst, const char* src);
|
||||
void ISONameFromAnimationName(char* dst, const char* src);
|
||||
void assert_file_exists(const char* path, const char* error_message);
|
||||
} // namespace file_util
|
||||
|
|
|
@ -10311,39 +10311,43 @@
|
|||
; )
|
||||
; )
|
||||
|
||||
; ;; rpc-h
|
||||
; (deftype rpc-buffer (basic)
|
||||
; ((elt-size uint32 :offset-assert 4)
|
||||
; (elt-count uint32 :offset-assert 8)
|
||||
; (elt-used uint32 :offset-assert 12)
|
||||
; (busy basic :offset-assert 16)
|
||||
; (base uint32 :offset-assert 20)
|
||||
; (data UNKNOWN :dynamic :offset-assert 32)
|
||||
; )
|
||||
; :method-count-assert 9
|
||||
; :size-assert #x20
|
||||
; :flag-assert #x900000020
|
||||
; )
|
||||
;; rpc-h
|
||||
(deftype rpc-buffer (basic)
|
||||
((elt-size uint32 :offset-assert 4)
|
||||
(elt-count uint32 :offset-assert 8)
|
||||
(elt-used uint32 :offset-assert 12)
|
||||
(busy basic :offset-assert 16)
|
||||
(base pointer :offset-assert 20)
|
||||
(data uint8 :dynamic :offset 32)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x20
|
||||
:flag-assert #x900000020
|
||||
(:methods
|
||||
(new (symbol type uint uint) rpc-buffer 0)
|
||||
)
|
||||
)
|
||||
|
||||
; ;; rpc-h
|
||||
; (deftype rpc-buffer-pair (basic)
|
||||
; ((buffer UNKNOWN 2 :offset-assert 4)
|
||||
; (current basic :offset-assert 12)
|
||||
; (last-recv-buffer uint32 :offset-assert 16)
|
||||
; (rpc-port int32 :offset-assert 20)
|
||||
; )
|
||||
; :method-count-assert 15
|
||||
; :size-assert #x18
|
||||
; :flag-assert #xf00000018
|
||||
; (:methods
|
||||
; (dummy-9 () none 9)
|
||||
; (dummy-10 () none 10)
|
||||
; (dummy-11 () none 11)
|
||||
; (dummy-12 () none 12)
|
||||
; (dummy-13 () none 13)
|
||||
; (dummy-14 () none 14)
|
||||
; )
|
||||
; )
|
||||
;; rpc-h
|
||||
(deftype rpc-buffer-pair (basic)
|
||||
((buffer rpc-buffer 2 :offset-assert 4)
|
||||
(current rpc-buffer :offset-assert 12)
|
||||
(last-recv-buffer pointer :offset-assert 16)
|
||||
(rpc-port int32 :offset-assert 20)
|
||||
)
|
||||
:method-count-assert 15
|
||||
:size-assert #x18
|
||||
:flag-assert #xf00000018
|
||||
(:methods
|
||||
(new (symbol type uint uint int) rpc-buffer-pair 0)
|
||||
(call (rpc-buffer-pair uint pointer uint) int 9)
|
||||
(add-element (rpc-buffer-pair) pointer 10)
|
||||
(decrement-elt-used (rpc-buffer-pair) int 11)
|
||||
(sync (rpc-buffer-pair symbol) int 12)
|
||||
(check-busy (rpc-buffer-pair) symbol 13)
|
||||
(pop-last-received (rpc-buffer-pair) pointer 14)
|
||||
)
|
||||
)
|
||||
|
||||
; ;; path-h
|
||||
; (deftype path-control (basic)
|
||||
|
@ -10659,7 +10663,8 @@
|
|||
(b1 uint32 :offset-assert 4)
|
||||
(b2 uint32 :offset-assert 8)
|
||||
(bt uint32 :offset-assert 12)
|
||||
(name uint128 :offset-assert 16)
|
||||
;(name uint128 :offset-assert 16)
|
||||
(name uint8 16 :offset-assert 16)
|
||||
(address uint32 :offset 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
|
@ -10667,30 +10672,30 @@
|
|||
:flag-assert #x900000020
|
||||
)
|
||||
|
||||
; ;; load-dgo
|
||||
; (deftype load-chunk-msg (structure)
|
||||
; ((rsvd uint16 :offset-assert 0)
|
||||
; (result uint16 :offset-assert 2)
|
||||
; (address uint32 :offset-assert 4)
|
||||
; (section uint32 :offset-assert 8)
|
||||
; (maxlen uint32 :offset-assert 12)
|
||||
; (id uint32 :offset-assert 4)
|
||||
; (basename UNKNOWN 48 :offset-assert 16)
|
||||
; )
|
||||
; :method-count-assert 9
|
||||
; :size-assert #x40
|
||||
; :flag-assert #x900000040
|
||||
; )
|
||||
;; load-dgo
|
||||
(deftype load-chunk-msg (structure)
|
||||
((rsvd uint16 :offset-assert 0)
|
||||
(result uint16 :offset-assert 2)
|
||||
(address uint32 :offset-assert 4)
|
||||
(section uint32 :offset-assert 8)
|
||||
(maxlen uint32 :offset-assert 12)
|
||||
(id uint32 :offset 4)
|
||||
(basename uint8 48 :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x40
|
||||
:flag-assert #x900000040
|
||||
)
|
||||
|
||||
; ;; load-dgo
|
||||
; (deftype dgo-header (structure)
|
||||
; ((length uint32 :offset-assert 0)
|
||||
; (rootname UNKNOWN 60 :offset-assert 4)
|
||||
; )
|
||||
; :method-count-assert 9
|
||||
; :size-assert #x40
|
||||
; :flag-assert #x900000040
|
||||
; )
|
||||
;; load-dgo
|
||||
(deftype dgo-header (structure)
|
||||
((length uint32 :offset-assert 0)
|
||||
(rootname uint8 60 :offset-assert 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x40
|
||||
:flag-assert #x900000040
|
||||
)
|
||||
|
||||
; ;; ramdisk
|
||||
; (deftype ramdisk-rpc-fill (structure)
|
||||
|
@ -31160,7 +31165,7 @@
|
|||
(define-extern string-strip-whitespace! function)
|
||||
(define-extern string<? function)
|
||||
(define-extern string-get-flag!! function)
|
||||
(define-extern charp<-string function)
|
||||
(define-extern charp<-string (function (pointer uint8) string int))
|
||||
(define-extern string>=? function)
|
||||
(define-extern string-charp= function)
|
||||
(define-extern string->float function)
|
||||
|
@ -32848,13 +32853,13 @@
|
|||
(define-extern dgo-load-begin function)
|
||||
(define-extern dgo-load-continue function)
|
||||
(define-extern destroy-mem function)
|
||||
(define-extern str-load function)
|
||||
(define-extern str-load (function string int pointer int symbol))
|
||||
;;(define-extern *load-str-rpc* object) ;; unknown type
|
||||
;;(define-extern load-chunk-msg object) ;; unknown type
|
||||
;;(define-extern *dgo-name* object) ;; unknown type
|
||||
(define-extern str-ambient-play function)
|
||||
;;(define-extern *load-str-lock* object) ;; unknown type
|
||||
(define-extern str-load-status function)
|
||||
(define-extern str-load-status (function (pointer int32) symbol))
|
||||
(define-extern str-load-cancel function)
|
||||
(define-extern str-play-queue function)
|
||||
(define-extern str-ambient-stop function)
|
||||
|
|
|
@ -6,27 +6,17 @@
|
|||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "game/overlord/isocommon.h"
|
||||
#include "game/common/overlord_common.h"
|
||||
#include "game/common/str_rpc_types.h"
|
||||
#include "StrFileReader.h"
|
||||
|
||||
// up to 64 chunks per STR file.
|
||||
constexpr int SECTOR_TABLE_SIZE = 64;
|
||||
|
||||
// there is a 1 sector long header
|
||||
struct StrFileHeader {
|
||||
u32 sectors[SECTOR_TABLE_SIZE]; // start of chunk, in sectors. including this sector.
|
||||
u32 sizes[SECTOR_TABLE_SIZE]; // size of chunk, in bytes. always an integer number of sectors.
|
||||
u32 pad[512 - 128]; // all zero
|
||||
};
|
||||
static_assert(sizeof(StrFileHeader) == SECTOR_SIZE, "Sector header size");
|
||||
|
||||
StrFileReader::StrFileReader(const std::string& file_path) {
|
||||
auto data = file_util::read_binary_file(file_path);
|
||||
assert(data.size() >= SECTOR_SIZE); // must have at least the header sector
|
||||
assert(data.size() % SECTOR_SIZE == 0); // should be multiple of the sector size.
|
||||
int end_sector = int(data.size()) / SECTOR_SIZE;
|
||||
|
||||
auto* header = (StrFileHeader*)data.data();
|
||||
auto* header = (StrFileHeaderSector*)data.data();
|
||||
|
||||
bool got_zero = false;
|
||||
for (int i = 0; i < SECTOR_TABLE_SIZE; i++) {
|
||||
|
|
3
game/common/overlord_common.h
Normal file
3
game/common/overlord_common.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
constexpr int SECTOR_SIZE = 0x800; // media sector size
|
37
game/common/str_rpc_types.h
Normal file
37
game/common/str_rpc_types.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "game/common/overlord_common.h"
|
||||
|
||||
constexpr int STR_RPC_ID = 0xdeb5;
|
||||
constexpr int STR_RPC_CHANNEL = 4;
|
||||
|
||||
struct RPC_Str_Cmd {
|
||||
u16 rsvd; // 0, seems unused
|
||||
u16 result; // 2, return code. see STR_RPC_RESULT_XXX
|
||||
u32 ee_addr; // 4, GOAL address to load to.
|
||||
s32 chunk_id; // 8, chunk ID for chunked file. Use -1 to load a non-chunked file, which gets the
|
||||
// whole file.
|
||||
u32 length; // 12, length that was actually loaded
|
||||
char name[64]; // file name
|
||||
};
|
||||
|
||||
constexpr int STR_RPC_RESULT_ERROR = 1;
|
||||
constexpr int STR_RPC_RESULT_DONE = 0;
|
||||
|
||||
// maximum number of chunks in a chunked file.
|
||||
constexpr int SECTOR_TABLE_SIZE = 64;
|
||||
|
||||
// the header of a chunked file
|
||||
struct StrFileHeader {
|
||||
u32 sectors[SECTOR_TABLE_SIZE]; // start of chunk, in sectors. including this sector.
|
||||
u32 sizes[SECTOR_TABLE_SIZE]; // size of chunk, in bytes. always an integer number of sectors
|
||||
};
|
||||
|
||||
// the first sector of a chunked file.
|
||||
struct StrFileHeaderSector : StrFileHeader {
|
||||
u32 pad[512 - 128]; // all zero
|
||||
};
|
||||
|
||||
static_assert(sizeof(StrFileHeader) == 0x200, "Sector header size");
|
||||
static_assert(sizeof(StrFileHeaderSector) == SECTOR_SIZE, "Sector header size");
|
|
@ -8,3 +8,5 @@ TEST.CGO resources/TEST.CGO
|
|||
TWEAKVAL.MUS resources/TWEAKVAL.MUS
|
||||
VAGDIR.AYB resources/VAGDIR.AYB
|
||||
SCREEN1.USA resources/SCREEN1.USA
|
||||
0COMMON.TXT out/iso/0COMMON.TXT
|
||||
0TEST.TXT out/iso/0TEST.TXT
|
|
@ -16,6 +16,7 @@
|
|||
#include "game/common/ramdisk_rpc_types.h"
|
||||
#include "game/common/loader_rpc_types.h"
|
||||
#include "game/common/play_rpc_types.h"
|
||||
#include "game/common/str_rpc_types.h"
|
||||
#include "third-party/spdlog/include/spdlog/spdlog.h"
|
||||
|
||||
using namespace ee;
|
||||
|
@ -49,6 +50,27 @@ s32 RpcCall(s32 rpcChannel,
|
|||
nullptr);
|
||||
}
|
||||
|
||||
// Terrible hack! Remove soon!
|
||||
|
||||
namespace {
|
||||
struct RpcCallArgCache {
|
||||
s32 rpcChannel;
|
||||
u32 fno;
|
||||
u32 async;
|
||||
} rpc_arg_cache;
|
||||
} // namespace
|
||||
|
||||
void RpcCall_wrapper_part1(s32 rpcChannel, u32 fno, u32 async) {
|
||||
rpc_arg_cache.rpcChannel = rpcChannel;
|
||||
rpc_arg_cache.fno = fno;
|
||||
rpc_arg_cache.async = async;
|
||||
}
|
||||
|
||||
u64 RpcCall_wrapper_part2(u64 send_buff, s32 send_size, u64 recv_buff, s32 recv_size) {
|
||||
return RpcCall_wrapper(rpc_arg_cache.rpcChannel, rpc_arg_cache.fno, rpc_arg_cache.async,
|
||||
send_buff, send_size, recv_buff, recv_size);
|
||||
}
|
||||
|
||||
/*!
|
||||
* GOAL Wrapper for RpcCall.
|
||||
*/
|
||||
|
@ -59,6 +81,7 @@ u64 RpcCall_wrapper(s32 rpcChannel,
|
|||
s32 send_size,
|
||||
u64 recv_buff,
|
||||
s32 recv_size) {
|
||||
fprintf(stderr, "size in c is %d\n", recv_size);
|
||||
return sceSifCallRpc(&cd[rpcChannel], fno, async, Ptr<u8>(send_buff).c(), send_size,
|
||||
Ptr<u8>(recv_buff).c(), recv_size, nullptr, nullptr);
|
||||
}
|
||||
|
@ -126,7 +149,7 @@ u32 RpcBind(s32 channel, s32 id) {
|
|||
u32 InitRPC() {
|
||||
if (!RpcBind(PLAYER_RPC_CHANNEL, PLAYER_RPC_ID) && !RpcBind(LOADER_RPC_CHANNEL, LOADER_RPC_ID) &&
|
||||
!RpcBind(RAMDISK_RPC_CHANNEL, RAMDISK_RPC_ID) && !RpcBind(DGO_RPC_CHANNEL, DGO_RPC_ID) &&
|
||||
!RpcBind(4, 0xdeb5) && !RpcBind(PLAY_RPC_CHANNEL, PLAY_RPC_ID)) {
|
||||
!RpcBind(STR_RPC_CHANNEL, STR_RPC_ID) && !RpcBind(PLAY_RPC_CHANNEL, PLAY_RPC_ID)) {
|
||||
return 0;
|
||||
}
|
||||
printf("Entering endless loop ... please wait\n");
|
||||
|
|
|
@ -29,4 +29,6 @@ u64 RpcCall_wrapper(s32 rpcChannel,
|
|||
u32 RpcBusy(s32 channel);
|
||||
void LoadDGOTest();
|
||||
|
||||
void RpcCall_wrapper_part1(s32 rpcChannel, u32 fno, u32 async);
|
||||
u64 RpcCall_wrapper_part2(u64 send_buff, s32 send_size, u64 recv_buff, s32 recv_size);
|
||||
#endif // JAK_V2_KDGO_H
|
||||
|
|
|
@ -25,4 +25,8 @@ void InitSoundScheme() {
|
|||
make_function_symbol_from_c("rpc-call", (void*)RpcCall_wrapper);
|
||||
make_function_symbol_from_c("rpc-busy?", (void*)RpcBusy);
|
||||
make_function_symbol_from_c("test-load-dgo-c", (void*)LoadDGOTest);
|
||||
|
||||
// terrible hack!
|
||||
make_function_symbol_from_c("rpc-call-p1", (void*)RpcCall_wrapper_part1);
|
||||
make_function_symbol_from_c("rpc-call-p2", (void*)RpcCall_wrapper_part2);
|
||||
}
|
|
@ -79,26 +79,10 @@ void fake_iso_init_globals() {
|
|||
int FS_Init(u8* buffer) {
|
||||
(void)buffer;
|
||||
|
||||
// get path to next/data/fake_iso.txt, the map file.
|
||||
char fakeiso_path[512];
|
||||
strcpy(fakeiso_path, file_util::get_file_path({"game", "fake_iso.txt"}).c_str());
|
||||
|
||||
// open the map.
|
||||
FILE* fp = fopen(fakeiso_path, "r");
|
||||
assert(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t len = ftell(fp);
|
||||
rewind(fp);
|
||||
char* fakeiso = (char*)malloc(len + 1);
|
||||
if (fread(fakeiso, len, 1, fp) != 1) {
|
||||
#ifdef __linux__
|
||||
assert(false);
|
||||
#endif
|
||||
}
|
||||
fakeiso[len] = '\0';
|
||||
auto config_str = file_util::read_text_file(file_util::get_file_path({"game", "fake_iso.txt"}));
|
||||
const char* ptr = config_str.c_str();
|
||||
|
||||
// loop over lines
|
||||
char* ptr = fakeiso;
|
||||
while (*ptr) {
|
||||
// newlines
|
||||
while (*ptr && *ptr == '\n')
|
||||
|
@ -127,7 +111,7 @@ int FS_Init(u8* buffer) {
|
|||
}
|
||||
|
||||
i = 0;
|
||||
while (*ptr && (*ptr != '\n') && (*ptr != ' ') && i < 128) {
|
||||
while (*ptr && (*ptr != '\n') && (*ptr != ' ') && (*ptr != EOF) && i < 128) {
|
||||
e->file_path[i] = *ptr;
|
||||
ptr++;
|
||||
i++;
|
||||
|
@ -145,8 +129,6 @@ int FS_Init(u8* buffer) {
|
|||
sFiles[i].location = i;
|
||||
}
|
||||
|
||||
free(fakeiso);
|
||||
|
||||
// TODO load tweak music.
|
||||
|
||||
return 0;
|
||||
|
@ -201,6 +183,7 @@ static const char* get_file_path(FileRecord* fr) {
|
|||
*/
|
||||
uint32_t FS_GetLength(FileRecord* fr) {
|
||||
const char* path = get_file_path(fr);
|
||||
file_util::assert_file_exists(path, "fake_iso FS_GetLength");
|
||||
FILE* fp = fopen(path, "rb");
|
||||
assert(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
|
|
@ -43,7 +43,7 @@ s32 str_thread;
|
|||
s32 play_thread;
|
||||
u8 gVagDir[VAGDIR_SIZE];
|
||||
u32 gPlayPos;
|
||||
RPC_Dgo_Cmd sRPCBuff[1]; // todo move...
|
||||
static RPC_Dgo_Cmd sRPCBuff[1]; // todo move...
|
||||
DgoCommand scmd;
|
||||
|
||||
void iso_init_globals() {
|
||||
|
@ -171,16 +171,16 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// thread_param.attr = TH_C;
|
||||
// thread_param.initPriority = 97;
|
||||
// thread_param.stackSize = 0x800;
|
||||
// thread_param.option = 0;
|
||||
// thread_param.entry = (void*)STRThread;
|
||||
// strcpy(thread_param.name, "STRThread");
|
||||
// str_thread = CreateThread(&thread_param);
|
||||
// if(str_thread <= 0) {
|
||||
// return 1;
|
||||
// }
|
||||
thread_param.attr = TH_C;
|
||||
thread_param.initPriority = 97;
|
||||
thread_param.stackSize = 0x800;
|
||||
thread_param.option = 0;
|
||||
thread_param.entry = (void*)STRThread;
|
||||
strcpy(thread_param.name, "STRThread");
|
||||
str_thread = CreateThread(&thread_param);
|
||||
if (str_thread <= 0) {
|
||||
return 1;
|
||||
}
|
||||
//
|
||||
// thread_param.attr = TH_C;
|
||||
// thread_param.initPriority = 97;
|
||||
|
@ -196,7 +196,7 @@ u32 InitISOFS(const char* fs_mode, const char* loading_screen) {
|
|||
// Start the threads!
|
||||
StartThread(iso_thread, 0);
|
||||
StartThread(dgo_thread, 0);
|
||||
// StartThread(str_thread, 0);
|
||||
StartThread(str_thread, 0);
|
||||
// StartThread(play_thread, 0);
|
||||
|
||||
// wait for ISO Thread to initialize
|
||||
|
|
|
@ -7,7 +7,7 @@ using namespace iop;
|
|||
/*!
|
||||
* Load a File to IOP memory (blocking)
|
||||
*/
|
||||
void LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length) {
|
||||
s32 LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length) {
|
||||
// printf("[OVERLORD] LoadISOFileToIOP %s, %d/%d bytes\n", file->name, length, file->size);
|
||||
spdlog::debug("[OVERLORD] LoadISOFileToIOP {}, {}/{} bytes", file->name, length, file->size);
|
||||
IsoCommandLoadSingle cmd;
|
||||
|
@ -23,12 +23,14 @@ void LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length) {
|
|||
if (cmd.status) {
|
||||
cmd.length_to_copy = 0;
|
||||
}
|
||||
|
||||
return cmd.length_to_copy;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Load a File to IOP memory (blocking)
|
||||
*/
|
||||
void LoadISOFileToEE(FileRecord* file, uint32_t addr, uint32_t length) {
|
||||
s32 LoadISOFileToEE(FileRecord* file, uint32_t addr, uint32_t length) {
|
||||
// printf("[OVERLORD] LoadISOFileToEE %s, %d/%d bytes\n", file->name, length, file->size);
|
||||
spdlog::debug("[OVERLORD] LoadISOFileToEE {}, {}/{} bytes", file->name, length, file->size);
|
||||
IsoCommandLoadSingle cmd;
|
||||
|
@ -44,4 +46,24 @@ void LoadISOFileToEE(FileRecord* file, uint32_t addr, uint32_t length) {
|
|||
if (cmd.status) {
|
||||
cmd.length_to_copy = 0;
|
||||
}
|
||||
|
||||
return cmd.length_to_copy;
|
||||
}
|
||||
|
||||
s32 LoadISOFileChunkToEE(FileRecord* file, uint32_t dest_addr, uint32_t length, uint32_t offset) {
|
||||
spdlog::debug("[OVERLORD] LoadISOFileChunkToEE {} : {} offset {}\n", file->name, length, offset);
|
||||
IsoCommandLoadSingle cmd;
|
||||
cmd.cmd_id = LOAD_TO_EE_OFFSET_CMD_ID;
|
||||
cmd.messagebox_to_reply = 0;
|
||||
cmd.thread_id = GetThreadId();
|
||||
cmd.file_record = file;
|
||||
cmd.dest_addr = (u8*)(u64)dest_addr;
|
||||
cmd.length = length;
|
||||
cmd.offset = offset;
|
||||
SendMbx(iso_mbx, &cmd);
|
||||
SleepThread();
|
||||
if (cmd.status) {
|
||||
cmd.length_to_copy = 0;
|
||||
}
|
||||
return cmd.length_to_copy;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef JAK_V2_ISO_API_H
|
||||
#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);
|
||||
|
||||
#endif // JAK_V2_ISO_API_H
|
||||
s32 LoadISOFileToIOP(FileRecord* file, void* addr, uint32_t length);
|
||||
s32 LoadISOFileToEE(FileRecord* file, uint32_t ee_addr, uint32_t length);
|
||||
s32 LoadISOFileChunkToEE(FileRecord* file, uint32_t dest_addr, uint32_t length, uint32_t offset);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
#include "common/link_types.h"
|
||||
#include "game/common/overlord_common.h"
|
||||
|
||||
constexpr int PRI_STACK_LENGTH = 4; // number of queued commands per priority
|
||||
constexpr int N_PRIORITIES = 4; // number of priorities
|
||||
|
@ -30,7 +31,6 @@ constexpr int LOAD_TO_IOP_CMD_ID = 0x101; // command to load to iop
|
|||
constexpr int LOAD_TO_EE_OFFSET_CMD_ID = 0x102; // command to load file to ee with offset.
|
||||
constexpr int LOAD_DGO_CMD_ID = 0x200; // command to load DGO
|
||||
|
||||
constexpr int SECTOR_SIZE = 0x800; // media sector size
|
||||
constexpr int MAX_ISO_FILES = 350; // maximum files on FS
|
||||
constexpr int MAX_OPEN_FILES = 16; // maximum number of open files at a time.
|
||||
|
||||
|
@ -51,7 +51,7 @@ struct FileRecord {
|
|||
*/
|
||||
struct LoadStackEntry {
|
||||
FileRecord* fr;
|
||||
uint32_t location;
|
||||
uint32_t location; // sectors.
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -185,5 +185,6 @@ extern IsoFs* isofs;
|
|||
extern s32 iso_mbx;
|
||||
|
||||
void MakeISOName(char* dst, const char* src);
|
||||
void ISONameFromAnimationName(char* dst, const char* src);
|
||||
|
||||
#endif // JAK_V2_ISOCOMMON_H
|
||||
|
|
|
@ -1,12 +1,141 @@
|
|||
#include <assert.h>
|
||||
#include "stream.h"
|
||||
/*!
|
||||
* @file stream.cpp
|
||||
* OVERLORD streaming driver.
|
||||
* Supports loading a file directly to the EE, or loading chunks of a chunked file.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include "stream.h"
|
||||
#include "game/sce/iop.h"
|
||||
#include "game/common/str_rpc_types.h"
|
||||
#include "game/overlord/isocommon.h"
|
||||
#include "game/overlord/iso_api.h"
|
||||
|
||||
using namespace iop;
|
||||
|
||||
static RPC_Str_Cmd sRPCBuf;
|
||||
void* RPC_STR(unsigned int fno, void* _cmd, int y);
|
||||
|
||||
/*!
|
||||
* We cache the chunk file headers so we can avoid seeking to the chunk header each time we
|
||||
* need to load another chunk, even if we load chunks out of order.
|
||||
*/
|
||||
struct CacheEntry {
|
||||
// the record for the chunk file described.
|
||||
FileRecord* fr = nullptr;
|
||||
// counts down from INT32_MAX - 1 each time we have a cache miss.
|
||||
s32 countdown = 0;
|
||||
// the actual cached data.
|
||||
StrFileHeader header;
|
||||
};
|
||||
|
||||
// the actual header cache.
|
||||
constexpr int STR_INDEX_CACHE_SIZE = 4;
|
||||
CacheEntry sCache[STR_INDEX_CACHE_SIZE];
|
||||
|
||||
void stream_init_globals() {
|
||||
memset(&sRPCBuf, 0, sizeof(RPC_Str_Cmd));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Run the STR RPC handler.
|
||||
*/
|
||||
u32 STRThread() {
|
||||
assert(false);
|
||||
sceSifQueueData dq;
|
||||
sceSifServeData serve;
|
||||
|
||||
CpuDisableIntr();
|
||||
sceSifInitRpc(0);
|
||||
sceSifSetRpcQueue(&dq, GetThreadId());
|
||||
sceSifRegisterRpc(&serve, STR_RPC_ID, RPC_STR, &sRPCBuf, nullptr, nullptr, &dq);
|
||||
CpuEnableIntr();
|
||||
sceSifRpcLoop(&dq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 PLAYThread() {
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* The STR RPC handler.
|
||||
*/
|
||||
void* RPC_STR(unsigned int fno, void* _cmd, int y) {
|
||||
(void)fno;
|
||||
(void)y;
|
||||
auto* cmd = (RPC_Str_Cmd*)_cmd;
|
||||
printf("RPC STR runs!\n");
|
||||
if (cmd->chunk_id < 0) {
|
||||
// it's _not_ a stream file. So we just treat it like a normal load.
|
||||
|
||||
// find the file with the given name
|
||||
auto file_record = isofs->find(cmd->name);
|
||||
if (file_record == nullptr) {
|
||||
// file not found!
|
||||
printf("[OVERLORD STR] Failed to find file %s for loading.\n", cmd->name);
|
||||
cmd->result = STR_RPC_RESULT_ERROR;
|
||||
} else {
|
||||
// load directly to the EE
|
||||
cmd->length = LoadISOFileToEE(file_record, cmd->ee_addr, cmd->length);
|
||||
if (cmd->length) {
|
||||
// successful load!
|
||||
cmd->result = STR_RPC_RESULT_DONE;
|
||||
} else {
|
||||
// there was an error loading.
|
||||
cmd->result = STR_RPC_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// it's a chunked file. These are only animations - these have a separate naming scheme.
|
||||
char animation_iso_name[128];
|
||||
ISONameFromAnimationName(animation_iso_name, cmd->name);
|
||||
auto file_record = isofs->find_in(animation_iso_name);
|
||||
|
||||
if (!file_record) {
|
||||
// didn't find the file
|
||||
printf("[OVERLORD STR] Failed to find animation %s\n", cmd->name);
|
||||
cmd->result = STR_RPC_RESULT_ERROR;
|
||||
} else {
|
||||
// found it! See if we've cached this animation's header.
|
||||
int cache_entry = 0;
|
||||
int oldest = INT32_MAX;
|
||||
int oldest_idx = -1;
|
||||
while (cache_entry < STR_INDEX_CACHE_SIZE && sCache[cache_entry].fr != file_record) {
|
||||
sCache[cache_entry].countdown--;
|
||||
if (sCache[cache_entry].countdown < oldest) {
|
||||
oldest_idx = cache_entry;
|
||||
oldest = sCache[cache_entry].countdown;
|
||||
}
|
||||
cache_entry++;
|
||||
}
|
||||
|
||||
if (cache_entry == STR_INDEX_CACHE_SIZE) {
|
||||
// cache miss, we need to load the header to the header cache on the IOP
|
||||
cache_entry = oldest_idx;
|
||||
sCache[oldest_idx].fr = file_record;
|
||||
sCache[oldest_idx].countdown = INT32_MAX - 1;
|
||||
if (!LoadISOFileToIOP(file_record, &sCache[oldest_idx].header, sizeof(StrFileHeader))) {
|
||||
printf("[OVERLORD STR] Failed to load chunk file header for animation %s\n", cmd->name);
|
||||
cmd->result = 1;
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
|
||||
// load data, using the cached header to find the location of the chunk.
|
||||
if (!LoadISOFileChunkToEE(file_record, cmd->ee_addr,
|
||||
sCache[cache_entry].header.sizes[cmd->chunk_id],
|
||||
sCache[cache_entry].header.sectors[cmd->chunk_id])) {
|
||||
printf("[OVERLORD STR] Failed to load chunk %d for animation %s\n", cmd->chunk_id,
|
||||
cmd->name);
|
||||
cmd->result = 1;
|
||||
} else {
|
||||
// successful load!
|
||||
cmd->length = sCache[cache_entry].header.sizes[cmd->chunk_id];
|
||||
cmd->result = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("Command result %d\n", cmd->result);
|
||||
return cmd;
|
||||
}
|
|
@ -6,5 +6,6 @@
|
|||
#include "common/common_types.h"
|
||||
u32 STRThread();
|
||||
u32 PLAYThread();
|
||||
void stream_init_globals();
|
||||
|
||||
#endif // JAK_V2_STREAM_H
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "game/overlord/iso_cd.h"
|
||||
#include "game/overlord/overlord.h"
|
||||
#include "game/overlord/srpc.h"
|
||||
#include "game/overlord/stream.h"
|
||||
|
||||
#include "common/goal_constants.h"
|
||||
|
||||
|
@ -183,7 +184,7 @@ void iop_runner(SystemThreadInterface& iface) {
|
|||
// soundcommon
|
||||
srpc_init_globals();
|
||||
// ssound
|
||||
// stream
|
||||
stream_init_globals();
|
||||
|
||||
iface.initialization_complete();
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ s32 sceSifCallRpc(sceSifClientData* bd,
|
|||
assert(!end_para);
|
||||
assert(mode == 1); // async
|
||||
iop->kernel.sif_rpc(bd->rpcd.id, fno, mode, send, ssize, recv, rsize);
|
||||
iop->signal_run_iop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,3 +5,130 @@
|
|||
;; name in dgo: load-dgo
|
||||
;; dgos: GAME, ENGINE
|
||||
|
||||
(deftype load-dgo-msg (structure)
|
||||
((rsvd uint16 :offset-assert 0)
|
||||
(result uint16 :offset-assert 2)
|
||||
(b1 uint32 :offset-assert 4)
|
||||
(b2 uint32 :offset-assert 8)
|
||||
(bt uint32 :offset-assert 12)
|
||||
;(name uint128 :offset-assert 16)
|
||||
(name uint8 16 :offset-assert 16)
|
||||
(address uint32 :offset 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x20
|
||||
:flag-assert #x900000020
|
||||
)
|
||||
|
||||
#|
|
||||
struct RPC_Dgo_Cmd {
|
||||
uint16_t rsvd;
|
||||
uint16_t result;
|
||||
uint32_t buffer1;
|
||||
uint32_t buffer2;
|
||||
uint32_t buffer_heap_top;
|
||||
char name[16];
|
||||
};
|
||||
|#
|
||||
|
||||
(deftype load-chunk-msg (structure)
|
||||
((rsvd uint16 :offset-assert 0)
|
||||
(result uint16 :offset-assert 2)
|
||||
(address uint32 :offset-assert 4)
|
||||
(section uint32 :offset-assert 8)
|
||||
(maxlen uint32 :offset-assert 12)
|
||||
(id uint32 :offset 4)
|
||||
(basename uint8 48 :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x40
|
||||
:flag-assert #x900000040
|
||||
)
|
||||
|
||||
#|
|
||||
struct RPC_Str_Cmd {
|
||||
u16 rsvd; // 0, seems unused
|
||||
u16 result; // 2, return code. see STR_RPC_RESULT_XXX
|
||||
u32 ee_addr; // 4, GOAL address to load to.
|
||||
s32 chunk_id; // 8, chunk ID for chunked file. Use -1 to load a non-chunked file, which gets the
|
||||
// whole file.
|
||||
u32 length; // 12, length that was actually loaded
|
||||
char name[64]; // file name
|
||||
};
|
||||
|#
|
||||
|
||||
(deftype dgo-header (structure)
|
||||
((length uint32 :offset-assert 0)
|
||||
(rootname uint8 60 :offset-assert 4)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x40
|
||||
:flag-assert #x900000040
|
||||
)
|
||||
|
||||
#|
|
||||
struct DgoHeader {
|
||||
u32 object_count;
|
||||
char name[60];
|
||||
};
|
||||
|#
|
||||
|
||||
(define-extern *load-dgo-rpc* rpc-buffer-pair)
|
||||
(when (= 0 (the int *load-dgo-rpc*))
|
||||
;; we need to allocate the rpc buffers
|
||||
(set! *load-dgo-rpc* (new 'global 'rpc-buffer-pair (the uint 32) (the uint 1) 3)) ;; todo, constants
|
||||
(define *load-str-rpc* (new 'global 'rpc-buffer-pair (the uint 64) (the uint 1) 4)) ;; todo, constants
|
||||
(define *play-str-rpc* (new 'global 'rpc-buffer-pair (the uint 64) (the uint 2) 5))
|
||||
(define *load-str-lock* '#f)
|
||||
(define *que-str-lock* '#f)
|
||||
(define *dgo-name* (new 'global 'string 64 (the string '#f)))
|
||||
)
|
||||
|
||||
(defun str-load ((name string) (chunk-id int) (address pointer) (len int))
|
||||
"Begin a streaming load if possible!
|
||||
We must be able to grab the lock, and no streaming load in progress.
|
||||
Return if we actually start the load."
|
||||
;; call method 13
|
||||
(when (or (check-busy *load-str-rpc*)
|
||||
*load-str-lock*
|
||||
)
|
||||
(return-from #f '#f)
|
||||
)
|
||||
;; ok, we are good to start a load. begin by adding an element to the RPC buffer
|
||||
(let ((cmd (the load-chunk-msg (add-element *load-str-rpc*))))
|
||||
(set! (-> cmd result) 666)
|
||||
(set! (-> cmd address) address)
|
||||
(set! (-> cmd section) chunk-id)
|
||||
(set! (-> cmd maxlen) len)
|
||||
(charp<-string (-> cmd basename) name)
|
||||
(call *load-str-rpc* (the uint 0) (the pointer cmd) (the uint 32))
|
||||
(set! *load-str-lock* '#t)
|
||||
(set! *que-str-lock* '#t)
|
||||
'#t
|
||||
)
|
||||
)
|
||||
|
||||
(defun str-load-status ((length-out (pointer int32)))
|
||||
"Check the status of the str load.
|
||||
The 'busy status indicates it is still going
|
||||
The 'error status indicates the load failed.
|
||||
The 'complete status means the load is finished, and length-out contains the loaded length."
|
||||
|
||||
;; still going..
|
||||
(if (check-busy *load-str-rpc*)
|
||||
(return-from #f 'busy)
|
||||
)
|
||||
|
||||
;; not busy, we can free the lock
|
||||
(set! *load-str-lock* '#f)
|
||||
(set! *que-str-lock* '#t)
|
||||
;; grab the response
|
||||
(let ((response (the load-chunk-msg (pop-last-received *load-str-rpc*))))
|
||||
(if (= 1 (-> response result))
|
||||
(return-from #f 'error)
|
||||
)
|
||||
;; no error!
|
||||
(set! (-> length-out) (the int (-> response maxlen)))
|
||||
'complete
|
||||
)
|
||||
)
|
|
@ -5,3 +5,230 @@
|
|||
;; name in dgo: rpc-h
|
||||
;; dgos: GAME, ENGINE
|
||||
|
||||
;; an RPC buffer is a container of elements to send to the IOP.
|
||||
;; each element is size elt-size, and there are maximum of elt-count elements
|
||||
;; it is possible to use fewer elements than elt-count.
|
||||
;; the buffer is 64-byte aligned.
|
||||
(deftype rpc-buffer (basic)
|
||||
((elt-size uint32 :offset-assert 4)
|
||||
(elt-count uint32 :offset-assert 8)
|
||||
(elt-used uint32 :offset-assert 12)
|
||||
(busy basic :offset-assert 16) ;; are we being sent currently?
|
||||
(base pointer :offset-assert 20) ;; 64-byte aligned buffer of elts.
|
||||
;; I suspect this was 16-byte aligned for DMA purposes.
|
||||
(data uint8 :dynamic :offset 32)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type uint uint) rpc-buffer 0)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x20
|
||||
:flag-assert #x900000020
|
||||
)
|
||||
|
||||
(defmethod new rpc-buffer ((allocation symbol) (type-to-make type) (elt-size uint) (elt-count uint))
|
||||
"Create a new rpc-buffer with room for elt-count elements of elt-size.
|
||||
The element array is 64-byte aligned."
|
||||
;; we make room for a buffer of size elt-size * elt-count that is _64 byte_ aligned.
|
||||
(let ((obj (object-new (the int (+ (-> type-to-make size) 63 (* elt-size elt-count))))))
|
||||
(set! (-> obj elt-size) elt-size)
|
||||
(set! (-> obj elt-count) elt-count)
|
||||
(set! (-> obj elt-used) 0)
|
||||
(set! (-> obj busy) '#f)
|
||||
;(set! (-> obj base) (logand -64 (+ (the uint obj) 28 63)))
|
||||
;; base is the 64-byte aligned buffer.
|
||||
(set! (-> obj base) (the pointer (logand -64 (+ (the uint (-> obj data)) 63))))
|
||||
obj
|
||||
)
|
||||
)
|
||||
|
||||
;; An RPC buffer pair is a pair of two buffers that implement double buffering.
|
||||
;; The "current" buffer is the one being loaded on the EE.
|
||||
;; The other is referred to as the active buffer.
|
||||
;; This also supports receiving data, though it just gives you a plain pointer.
|
||||
(deftype rpc-buffer-pair (basic)
|
||||
((buffer rpc-buffer 2 :offset-assert 4) ;; the two buffers
|
||||
(current rpc-buffer :offset-assert 12) ;; the buffer being loaded
|
||||
(last-recv-buffer pointer :offset-assert 16) ;; the last reply
|
||||
(rpc-port int32 :offset-assert 20) ;; the RPC port number
|
||||
)
|
||||
:method-count-assert 15
|
||||
:size-assert #x18
|
||||
:flag-assert #xf00000018
|
||||
(:methods
|
||||
(new (symbol type uint uint int) rpc-buffer-pair 0)
|
||||
(call (rpc-buffer-pair uint pointer uint) int 9)
|
||||
(add-element (rpc-buffer-pair) pointer 10)
|
||||
(decrement-elt-used (rpc-buffer-pair) int 11)
|
||||
(sync (rpc-buffer-pair symbol) int 12)
|
||||
(check-busy (rpc-buffer-pair) symbol 13)
|
||||
(pop-last-received (rpc-buffer-pair) pointer 14)
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod new rpc-buffer-pair ((allocation symbol) (type-to-make type) (elt-size uint) (elt-count uint) (rpc-port int))
|
||||
"Create a new rpc-buffer-pair"
|
||||
(let ((obj (object-new)))
|
||||
(set! (-> obj buffer 0) (new 'global 'rpc-buffer elt-size elt-count))
|
||||
(set! (-> obj buffer 1) (new 'global 'rpc-buffer elt-size elt-count))
|
||||
(set! (-> obj current) (-> obj buffer 0))
|
||||
(set! (-> obj last-recv-buffer) (the pointer '#f))
|
||||
(set! (-> obj rpc-port) rpc-port)
|
||||
obj
|
||||
)
|
||||
)
|
||||
|
||||
;; method 12
|
||||
(defmethod sync rpc-buffer-pair ((obj rpc-buffer-pair) (print-stall-warning symbol))
|
||||
"Wait for the in progress RPC to complete."
|
||||
(let ((active-buffer (if (= (-> obj buffer 0) (-> obj current))
|
||||
(-> obj buffer 1)
|
||||
(-> obj buffer 0))
|
||||
)
|
||||
)
|
||||
|
||||
(when (-> active-buffer busy)
|
||||
;; the flag is set, meaning we should check.
|
||||
(cond
|
||||
((!= 0 (rpc-busy? (-> obj rpc-port)))
|
||||
;; we're busy
|
||||
(if print-stall-warning
|
||||
(format 0 "STALL: waiting for IOP on RPC port #~D~%" (-> obj rpc-port))
|
||||
)
|
||||
(while (!= 0 (rpc-busy? (-> obj rpc-port)))
|
||||
;; real game has a bunch of nops
|
||||
(+ 1 2 3)
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; not actually busy, clear the flag!
|
||||
(set! (-> active-buffer busy) '#f)
|
||||
(set! (-> active-buffer elt-used) 0)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
0
|
||||
)
|
||||
|
||||
;; method 13
|
||||
(defmethod check-busy rpc-buffer-pair ((obj rpc-buffer-pair))
|
||||
"Is the currently running RPC still busy?"
|
||||
(let ((active-buffer (if (= (-> obj buffer 0) (-> obj current))
|
||||
(-> obj buffer 1)
|
||||
(-> obj buffer 0)
|
||||
)))
|
||||
(when (-> active-buffer busy)
|
||||
(if (!= 0 (rpc-busy? (-> obj rpc-port)))
|
||||
(return-from #f '#t)
|
||||
)
|
||||
(set! (-> active-buffer busy) '#f)
|
||||
(set! (-> active-buffer elt-count) 0)
|
||||
)
|
||||
)
|
||||
'#f
|
||||
)
|
||||
|
||||
(defmacro hack-rpc-call (a0 a1 a2 a3 a4 a5 a6)
|
||||
`(begin
|
||||
(rpc-call-p1 ,a0 ,a1 ,a2)
|
||||
(rpc-call-p2 ,a3 ,a4 ,a5 ,a6)
|
||||
)
|
||||
)
|
||||
|
||||
;; method 9
|
||||
(defmethod call rpc-buffer-pair ((obj rpc-buffer-pair) (fno uint) (recv-buff pointer) (recv-size uint))
|
||||
"Call an RPC. This is an async RPC. Use check-busy or sync to see if it's done."
|
||||
(when (!= 0 (-> obj current elt-used))
|
||||
;; when we have used elements
|
||||
(format 0 "call rpc-buffer-pair with ~D elts~%" (-> obj current elt-used))
|
||||
|
||||
;; make sure the previous buffer is done
|
||||
(let ((active-buffer (if (= (-> obj buffer 0) (-> obj current))
|
||||
(-> obj buffer 1)
|
||||
(-> obj buffer 0))))
|
||||
(when (-> active-buffer busy)
|
||||
;; we think the active buffer may be busy.
|
||||
;; first lets just do a simple check
|
||||
(cond
|
||||
((!= 0 (rpc-busy? (-> obj rpc-port)))
|
||||
;; busy! print an error and stall!
|
||||
(format 0 "STALL: waiting for IOP on RPC port #~D~%" (-> obj rpc-port))
|
||||
(while (!= 0 (rpc-busy? (-> obj rpc-port)))
|
||||
(+ 1 2 3)
|
||||
)
|
||||
)
|
||||
(else
|
||||
;; not busy.
|
||||
(set! (-> active-buffer busy) '#f)
|
||||
(set! (-> active-buffer elt-used) 0)
|
||||
)
|
||||
)
|
||||
)
|
||||
;; now we've cleared the last RPC call, we can do another
|
||||
(let ((current-buffer (-> obj current)))
|
||||
;; rpc_channel, fno, async, send_buff, send_size, recv_buff, recv_size
|
||||
(format 0 "recv-size is ~D~%" recv-size)
|
||||
(hack-rpc-call (-> obj rpc-port)
|
||||
fno
|
||||
(the uint 1)
|
||||
(the uint (-> current-buffer base))
|
||||
(the int (* (-> current-buffer elt-used) (-> current-buffer elt-size)))
|
||||
(the uint recv-buff)
|
||||
(the int recv-size)
|
||||
)
|
||||
(set! (-> current-buffer busy) '#t)
|
||||
(set! (-> obj last-recv-buffer) recv-buff)
|
||||
(set! (-> obj current) active-buffer)
|
||||
)
|
||||
)
|
||||
)
|
||||
0
|
||||
)
|
||||
|
||||
|
||||
;; method 14
|
||||
(defmethod pop-last-received rpc-buffer-pair ((obj rpc-buffer-pair))
|
||||
(let ((result (-> obj last-recv-buffer)))
|
||||
(set! (-> obj last-recv-buffer) (the rpc-buffer '#f))
|
||||
result
|
||||
)
|
||||
)
|
||||
|
||||
;; method 10
|
||||
(defmethod add-element rpc-buffer-pair ((obj rpc-buffer-pair))
|
||||
"Add an element, and return a pointer to the element.
|
||||
If we are out of elements, flush by doing an RPC call.
|
||||
DANGER: this uses all arguments of 0. If you want something else, flush it yourself.
|
||||
If we're RPC 0 and we do this auto-flush, print a warning.
|
||||
"
|
||||
(let ((current-buffer (-> obj current)))
|
||||
(when (= (-> current-buffer elt-count) (-> current-buffer elt-used))
|
||||
;; oops, we're full.
|
||||
(if (= 0 (-> obj rpc-port))
|
||||
;; if we're RPC 0, this is evidently a situation to warn about.
|
||||
(format 0 "WARNING: too many sound commands queued~%")
|
||||
)
|
||||
;; otherwise we just flush
|
||||
;; seems kinda dangerous. these could be the wrong parameters...
|
||||
(call obj (the uint 0) (the pointer 0) (the uint 0))
|
||||
;; update the current-buffer.
|
||||
(set! current-buffer (-> obj current))
|
||||
)
|
||||
(let ((result (&+ (-> current-buffer base) (* (-> current-buffer elt-size) (-> current-buffer elt-used)))))
|
||||
(+! (-> current-buffer elt-used) 1)
|
||||
result
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; method 11
|
||||
(defmethod decrement-elt-used rpc-buffer-pair ((obj rpc-buffer-pair))
|
||||
"If elt-used > 0, decrease it by one."
|
||||
(when (> (-> obj current elt-used) 0)
|
||||
(-! (-> obj current elt-used) 1)
|
||||
)
|
||||
0
|
||||
)
|
|
@ -53,3 +53,4 @@
|
|||
;; todo print-game-text
|
||||
;; todo disable-level-text-file-loading
|
||||
;; todo enable-level-text-file-loading
|
||||
|
|
@ -352,6 +352,9 @@
|
|||
`(logand #xfffffff0 (+ (the-as integer ,value) 15))
|
||||
)
|
||||
|
||||
(defmacro align64 (value)
|
||||
`(logand -64 (+ (the-as int ,value) 63))
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; TYPE STUFF
|
||||
|
@ -410,7 +413,7 @@
|
|||
(defmacro object-new (&rest sz)
|
||||
(if (null? sz)
|
||||
`(the ,(current-method-type) ((method object new) allocation type-to-make (the int (-> type-to-make size))))
|
||||
`(the ,(current-method-type)((method object new) allocation type-to-make ,@sz))
|
||||
`(the ,(current-method-type) ((method object new) allocation type-to-make ,@sz))
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
(define-extern kmalloc (function kheap int int string))
|
||||
(define-extern new-dynamic-structure (function kheap type int structure))
|
||||
(define-extern method-set! (function type int function none)) ;; may actually return function.
|
||||
(define-extern link (function pointer string int kheap int pointer))
|
||||
(define-extern link (function pointer pointer int kheap int pointer))
|
||||
(define-extern dgo-load (function string kheap int int none))
|
||||
(define-extern link-begin (function pointer string int kheap int int))
|
||||
(define-extern link-resume (function int))
|
||||
|
@ -145,4 +145,14 @@
|
|||
;; *stack-size*
|
||||
;; *kernel-boot-message*
|
||||
;; *kernel-boot-mode*
|
||||
;; *kernel-boot-level*
|
||||
;; *kernel-boot-level*
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;; ksound - InitSoundScheme
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define-extern rpc-call (function int uint uint uint int uint int uint))
|
||||
(define-extern rpc-busy? (function int uint))
|
||||
;; hack! remove!
|
||||
(define-extern rpc-call-p1 (function int uint uint none))
|
||||
(define-extern rpc-call-p2 (function uint int uint int uint))
|
|
@ -57,4 +57,17 @@
|
|||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(defun charp<-string ((dst (pointer uint8)) (src-string string))
|
||||
"Copy a GOAL string into a character array."
|
||||
(let ((src (-> src-string data)))
|
||||
(while (!= 0 (-> src))
|
||||
(set! (-> dst) (-> src))
|
||||
(&+! dst 1)
|
||||
(&+! src 1)
|
||||
)
|
||||
(set! (-> dst) 0)
|
||||
0
|
||||
)
|
||||
)
|
|
@ -441,10 +441,11 @@ Val* Compiler::compile_real_function_call(const goos::Object& form,
|
|||
}
|
||||
for (uint32_t i = 0; i < args.size(); i++) {
|
||||
if (method_type_name.empty()) {
|
||||
typecheck(form, function->type().get_arg(i), args.at(i)->type(), "function argument");
|
||||
typecheck(form, function->type().get_arg(i), args.at(i)->type(),
|
||||
fmt::format("function argument {}", i));
|
||||
} else {
|
||||
typecheck(form, function->type().get_arg(i).substitute_for_method_call(method_type_name),
|
||||
args.at(i)->type(), "function argument");
|
||||
args.at(i)->type(), fmt::format("function argument {}", i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,38 @@
|
|||
|
||||
(start-test "game-text")
|
||||
|
||||
(let ((text (the game-text-info (load "$ISO/0TEST.TXT" *common-text-heap*))))
|
||||
(defun hack-load ()
|
||||
;(declare (inline))
|
||||
(str-load "0TEST.TXT"
|
||||
-1
|
||||
(the pointer (align64 (-> *common-text-heap* current)))
|
||||
; note, this max size is probably wrong because of the alignment.
|
||||
(the int (&- (-> *common-text-heap* top) (-> *common-text-heap* current)))
|
||||
)
|
||||
|
||||
|
||||
(sync *load-str-rpc* '#t)
|
||||
|
||||
(let* ((got-length (new 'stack 'array 'int32 1))
|
||||
(status (str-load-status got-length)))
|
||||
;(format #t "Status is ~A, length ~D~%" status (-> got-length))
|
||||
|
||||
;; failed!
|
||||
(if (!= status 'complete)
|
||||
(return-from #f #f)
|
||||
)
|
||||
|
||||
(link (the pointer (align64 (-> *common-text-heap* current)))
|
||||
(-> "test" data)
|
||||
(-> got-length)
|
||||
*common-text-heap*
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
(let ((text (the game-text-info (hack-load))))
|
||||
(format 0 "~I~%" text)
|
||||
(expect-true (= #x123 (-> text data 0 id)))
|
||||
(expect-true (= #x456 (-> text data 1 id)))
|
||||
|
|
Loading…
Reference in a new issue