mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +00:00
...+CellSyncQueue
This commit is contained in:
parent
3ab08e0d7a
commit
c9ad88b3ff
@ -30,14 +30,14 @@ namespace vm
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// atomically compare data with cmp, replace with exch if equal, return previous data value anyway
|
// atomically compare data with cmp, replace with exch if equal, return previous data value anyway
|
||||||
__forceinline const T compare_and_swap(const T cmp, const T exch) volatile
|
__forceinline const T compare_and_swap(const T& cmp, const T& exch) volatile
|
||||||
{
|
{
|
||||||
const atomic_type res = InterlockedCompareExchange((volatile atomic_type*)&data, (atomic_type&)exch, (atomic_type&)cmp);
|
const atomic_type res = InterlockedCompareExchange((volatile atomic_type*)&data, (atomic_type&)exch, (atomic_type&)cmp);
|
||||||
return (T&)res;
|
return (T&)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// atomically compare data with cmp, replace with exch if equal, return true if data was replaced
|
// atomically compare data with cmp, replace with exch if equal, return true if data was replaced
|
||||||
__forceinline bool compare_and_swap_test(const T cmp, const T exch) volatile
|
__forceinline bool compare_and_swap_test(const T& cmp, const T& exch) volatile
|
||||||
{
|
{
|
||||||
return InterlockedCompareExchange((volatile atomic_type*)&data, (atomic_type&)exch, (atomic_type&)cmp) == (atomic_type&)cmp;
|
return InterlockedCompareExchange((volatile atomic_type*)&data, (atomic_type&)exch, (atomic_type&)cmp) == (atomic_type&)cmp;
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ namespace vm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomically replace data with exch, return previous data value
|
// atomically replace data with exch, return previous data value
|
||||||
__forceinline const T exchange(const T exch) volatile
|
__forceinline const T exchange(const T& exch) volatile
|
||||||
{
|
{
|
||||||
const atomic_type res = InterlockedExchange((volatile atomic_type*)&data, (atomic_type&)exch);
|
const atomic_type res = InterlockedExchange((volatile atomic_type*)&data, (atomic_type&)exch);
|
||||||
return (T&)res;
|
return (T&)res;
|
||||||
@ -63,7 +63,7 @@ namespace vm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write data without memory barrier
|
// write data without memory barrier
|
||||||
__forceinline void write_relaxed(const T value) volatile
|
__forceinline void write_relaxed(const T& value) volatile
|
||||||
{
|
{
|
||||||
(T&)data = value;
|
(T&)data = value;
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ namespace vm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// perform atomic operation on data with special exit condition (if intermediate result != proceed_value)
|
// perform atomic operation on data with special exit condition (if intermediate result != proceed_value)
|
||||||
template<typename RT, typename FT> __forceinline RT atomic_op(const RT proceed_value, const FT atomic_proc) volatile
|
template<typename RT, typename FT> __forceinline RT atomic_op(const RT& proceed_value, const FT atomic_proc) volatile
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -93,37 +93,37 @@ namespace vm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline const T _or(const T right) volatile
|
__forceinline const T _or(const T& right) volatile
|
||||||
{
|
{
|
||||||
const atomic_type res = InterlockedOr((volatile atomic_type*)&data, (atomic_type&)right);
|
const atomic_type res = InterlockedOr((volatile atomic_type*)&data, (atomic_type&)right);
|
||||||
return (T&)res;
|
return (T&)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline const T _and(const T right) volatile
|
__forceinline const T _and(const T& right) volatile
|
||||||
{
|
{
|
||||||
const atomic_type res = InterlockedAnd((volatile atomic_type*)&data, (atomic_type&)right);
|
const atomic_type res = InterlockedAnd((volatile atomic_type*)&data, (atomic_type&)right);
|
||||||
return (T&)res;
|
return (T&)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline const T _xor(const T right) volatile
|
__forceinline const T _xor(const T& right) volatile
|
||||||
{
|
{
|
||||||
const atomic_type res = InterlockedXor((volatile atomic_type*)&data, (atomic_type&)right);
|
const atomic_type res = InterlockedXor((volatile atomic_type*)&data, (atomic_type&)right);
|
||||||
return (T&)res;
|
return (T&)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline const T operator |= (const T right) volatile
|
__forceinline const T operator |= (const T& right) volatile
|
||||||
{
|
{
|
||||||
const atomic_type res = InterlockedOr((volatile atomic_type*)&data, (atomic_type&)right) | (atomic_type&)right;
|
const atomic_type res = InterlockedOr((volatile atomic_type*)&data, (atomic_type&)right) | (atomic_type&)right;
|
||||||
return (T&)res;
|
return (T&)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline const T operator &= (const T right) volatile
|
__forceinline const T operator &= (const T& right) volatile
|
||||||
{
|
{
|
||||||
const atomic_type res = InterlockedAnd((volatile atomic_type*)&data, (atomic_type&)right) & (atomic_type&)right;
|
const atomic_type res = InterlockedAnd((volatile atomic_type*)&data, (atomic_type&)right) & (atomic_type&)right;
|
||||||
return (T&)res;
|
return (T&)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline const T operator ^= (const T right) volatile
|
__forceinline const T operator ^= (const T& right) volatile
|
||||||
{
|
{
|
||||||
const atomic_type res = InterlockedXor((volatile atomic_type*)&data, (atomic_type&)right) ^ (atomic_type&)right;
|
const atomic_type res = InterlockedXor((volatile atomic_type*)&data, (atomic_type&)right) ^ (atomic_type&)right;
|
||||||
return (T&)res;
|
return (T&)res;
|
||||||
|
@ -471,11 +471,10 @@ s32 syncQueueInitialize(vm::ptr<CellSyncQueue> queue, vm::ptr<u8> buffer, u32 si
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prx: zeroize first u64, write size in third u32, write depth in fourth u32, write address in third u64 and sync
|
// prx: zeroize first u64, write size in third u32, write depth in fourth u32, write address in third u64 and sync
|
||||||
queue->m_data() = 0;
|
|
||||||
queue->m_size = size;
|
queue->m_size = size;
|
||||||
queue->m_depth = depth;
|
queue->m_depth = depth;
|
||||||
queue->m_buffer = buffer;
|
queue->m_buffer = buffer;
|
||||||
InterlockedCompareExchange(&queue->m_data(), 0, 0);
|
queue->data.exchange({});
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,6 +485,26 @@ s32 cellSyncQueueInitialize(vm::ptr<CellSyncQueue> queue, vm::ptr<u8> buffer, u3
|
|||||||
return syncQueueInitialize(queue, buffer, size, depth);
|
return syncQueueInitialize(queue, buffer, size, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 syncQueueTryPushOp(CellSyncQueue::data_t& queue, u32 depth, u32& position)
|
||||||
|
{
|
||||||
|
const u32 v1 = (u32)queue.m_v1;
|
||||||
|
const u32 v2 = (u32)queue.m_v2;
|
||||||
|
// prx: compare 5th u8 with zero (break if not zero)
|
||||||
|
// prx: compare (second u32 (u24) + first u8) with depth (break if greater or equal)
|
||||||
|
if ((v2 >> 24) || ((v2 & 0xffffff) + (v1 >> 24)) >= depth)
|
||||||
|
{
|
||||||
|
return CELL_SYNC_ERROR_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prx: extract first u32 (u24) (-> position), calculate (position + 1) % depth, insert it back
|
||||||
|
// prx: insert 1 in 5th u8
|
||||||
|
// prx: extract second u32 (u24), increase it, insert it back
|
||||||
|
position = (v1 & 0xffffff);
|
||||||
|
queue.m_v1 = (v1 & 0xff000000) | ((position + 1) % depth);
|
||||||
|
queue.m_v2 = (1 << 24) | ((v2 & 0xffffff) + 1);
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
s32 cellSyncQueuePush(vm::ptr<CellSyncQueue> queue, vm::ptr<const void> buffer)
|
s32 cellSyncQueuePush(vm::ptr<CellSyncQueue> queue, vm::ptr<const void> buffer)
|
||||||
{
|
{
|
||||||
cellSync->Log("cellSyncQueuePush(queue_addr=0x%x, buffer_addr=0x%x)", queue.addr(), buffer.addr());
|
cellSync->Log("cellSyncQueuePush(queue_addr=0x%x, buffer_addr=0x%x)", queue.addr(), buffer.addr());
|
||||||
@ -501,52 +520,27 @@ s32 cellSyncQueuePush(vm::ptr<CellSyncQueue> queue, vm::ptr<const void> buffer)
|
|||||||
|
|
||||||
const u32 size = (u32)queue->m_size;
|
const u32 size = (u32)queue->m_size;
|
||||||
const u32 depth = (u32)queue->m_depth;
|
const u32 depth = (u32)queue->m_depth;
|
||||||
assert(((u32)queue->m_v1 & 0xffffff) <= depth && ((u32)queue->m_v2 & 0xffffff) <= depth);
|
assert(((u32)queue->data.read_relaxed().m_v1 & 0xffffff) <= depth && ((u32)queue->data.read_relaxed().m_v2 & 0xffffff) <= depth);
|
||||||
|
|
||||||
u32 position;
|
u32 position;
|
||||||
while (true)
|
while (queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
return syncQueueTryPushOp(queue, depth, position);
|
||||||
CellSyncQueue new_queue;
|
}))
|
||||||
new_queue.m_data() = old_data;
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||||
const u32 v1 = (u32)new_queue.m_v1;
|
if (Emu.IsStopped())
|
||||||
const u32 v2 = (u32)new_queue.m_v2;
|
|
||||||
// prx: compare 5th u8 with zero (repeat if not zero)
|
|
||||||
// prx: compare (second u32 (u24) + first u8) with depth (repeat if greater or equal)
|
|
||||||
if ((v2 >> 24) || ((v2 & 0xffffff) + (v1 >> 24)) >= depth)
|
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
cellSync->Warning("cellSyncQueuePush(queue_addr=0x%x) aborted", queue.addr());
|
||||||
if (Emu.IsStopped())
|
return CELL_OK;
|
||||||
{
|
|
||||||
cellSync->Warning("cellSyncQueuePush(queue_addr=0x%x) aborted", queue.addr());
|
|
||||||
return CELL_OK;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prx: extract first u32 (u24) (-> position), calculate (position + 1) % depth, insert it back
|
|
||||||
// prx: insert 1 in 5th u8
|
|
||||||
// prx: extract second u32 (u24), increase it, insert it back
|
|
||||||
position = (v1 & 0xffffff);
|
|
||||||
new_queue.m_v1 = (v1 & 0xff000000) | ((position + 1) % depth);
|
|
||||||
new_queue.m_v2 = (1 << 24) | ((v2 & 0xffffff) + 1);
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prx: memcpy(position * m_size + m_addr, buffer_addr, m_size), sync
|
// prx: memcpy(position * m_size + m_addr, buffer_addr, m_size), sync
|
||||||
memcpy(&queue->m_buffer[position * size], buffer.get_ptr(), size);
|
memcpy(&queue->m_buffer[position * size], buffer.get_ptr(), size);
|
||||||
|
|
||||||
// prx: atomically insert 0 in 5th u8
|
// prx: atomically insert 0 in 5th u8
|
||||||
while (true)
|
queue->data &= { be_t<u32>::make(~0), be_t<u32>::make(0xffffff) };
|
||||||
{
|
|
||||||
const u64 old_data = queue->m_data();
|
|
||||||
CellSyncQueue new_queue;
|
|
||||||
new_queue.m_data() = old_data;
|
|
||||||
|
|
||||||
new_queue.m_v2 &= 0xffffff; // TODO: use InterlockedAnd() or something
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,39 +559,39 @@ s32 cellSyncQueueTryPush(vm::ptr<CellSyncQueue> queue, vm::ptr<const void> buffe
|
|||||||
|
|
||||||
const u32 size = (u32)queue->m_size;
|
const u32 size = (u32)queue->m_size;
|
||||||
const u32 depth = (u32)queue->m_depth;
|
const u32 depth = (u32)queue->m_depth;
|
||||||
assert(((u32)queue->m_v1 & 0xffffff) <= depth && ((u32)queue->m_v2 & 0xffffff) <= depth);
|
assert(((u32)queue->data.read_relaxed().m_v1 & 0xffffff) <= depth && ((u32)queue->data.read_relaxed().m_v2 & 0xffffff) <= depth);
|
||||||
|
|
||||||
u32 position;
|
u32 position;
|
||||||
while (true)
|
if (s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
return syncQueueTryPushOp(queue, depth, position);
|
||||||
CellSyncQueue new_queue;
|
}))
|
||||||
new_queue.m_data() = old_data;
|
{
|
||||||
|
return res;
|
||||||
const u32 v1 = (u32)new_queue.m_v1;
|
|
||||||
const u32 v2 = (u32)new_queue.m_v2;
|
|
||||||
if ((v2 >> 24) || ((v2 & 0xffffff) + (v1 >> 24)) >= depth)
|
|
||||||
{
|
|
||||||
return CELL_SYNC_ERROR_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
position = (v1 & 0xffffff);
|
|
||||||
new_queue.m_v1 = (v1 & 0xff000000) | ((position + 1) % depth);
|
|
||||||
new_queue.m_v2 = (1 << 24) | ((v2 & 0xffffff) + 1);
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&queue->m_buffer[position * size], buffer.get_ptr(), size);
|
memcpy(&queue->m_buffer[position * size], buffer.get_ptr(), size);
|
||||||
|
queue->data &= { be_t<u32>::make(~0), be_t<u32>::make(0xffffff) };
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
s32 syncQueueTryPopOp(CellSyncQueue::data_t& queue, u32 depth, u32& position)
|
||||||
|
{
|
||||||
|
const u32 v1 = (u32)queue.m_v1;
|
||||||
|
const u32 v2 = (u32)queue.m_v2;
|
||||||
|
// prx: extract first u8, repeat if not zero
|
||||||
|
// prx: extract second u32 (u24), subtract 5th u8, compare with zero, repeat if less or equal
|
||||||
|
if ((v1 >> 24) || ((v2 & 0xffffff) <= (v2 >> 24)))
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
return CELL_SYNC_ERROR_BUSY;
|
||||||
CellSyncQueue new_queue;
|
|
||||||
new_queue.m_data() = old_data;
|
|
||||||
|
|
||||||
new_queue.m_v2 &= 0xffffff; // TODO: use InterlockedAnd() or something
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prx: insert 1 in first u8
|
||||||
|
// prx: extract first u32 (u24), add depth, subtract second u32 (u24), calculate (% depth), save to position
|
||||||
|
// prx: extract second u32 (u24), decrease it, insert it back
|
||||||
|
queue.m_v1 = 0x1000000 | v1;
|
||||||
|
position = ((v1 & 0xffffff) + depth - (v2 & 0xffffff)) % depth;
|
||||||
|
queue.m_v2 = (v2 & 0xff000000) | ((v2 & 0xffffff) - 1);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,52 +610,27 @@ s32 cellSyncQueuePop(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
|
|||||||
|
|
||||||
const u32 size = (u32)queue->m_size;
|
const u32 size = (u32)queue->m_size;
|
||||||
const u32 depth = (u32)queue->m_depth;
|
const u32 depth = (u32)queue->m_depth;
|
||||||
assert(((u32)queue->m_v1 & 0xffffff) <= depth && ((u32)queue->m_v2 & 0xffffff) <= depth);
|
assert(((u32)queue->data.read_relaxed().m_v1 & 0xffffff) <= depth && ((u32)queue->data.read_relaxed().m_v2 & 0xffffff) <= depth);
|
||||||
|
|
||||||
u32 position;
|
u32 position;
|
||||||
while (true)
|
while (queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
return syncQueueTryPopOp(queue, depth, position);
|
||||||
CellSyncQueue new_queue;
|
}))
|
||||||
new_queue.m_data() = old_data;
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||||
const u32 v1 = (u32)new_queue.m_v1;
|
if (Emu.IsStopped())
|
||||||
const u32 v2 = (u32)new_queue.m_v2;
|
|
||||||
// prx: extract first u8, repeat if not zero
|
|
||||||
// prx: extract second u32 (u24), subtract 5th u8, compare with zero, repeat if less or equal
|
|
||||||
if ((v1 >> 24) || ((v2 & 0xffffff) <= (v2 >> 24)))
|
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
cellSync->Warning("cellSyncQueuePop(queue_addr=0x%x) aborted", queue.addr());
|
||||||
if (Emu.IsStopped())
|
return CELL_OK;
|
||||||
{
|
|
||||||
cellSync->Warning("cellSyncQueuePop(queue_addr=0x%x) aborted", queue.addr());
|
|
||||||
return CELL_OK;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prx: insert 1 in first u8
|
|
||||||
// prx: extract first u32 (u24), add depth, subtract second u32 (u24), calculate (% depth), save to position
|
|
||||||
// prx: extract second u32 (u24), decrease it, insert it back
|
|
||||||
new_queue.m_v1 = 0x1000000 | v1;
|
|
||||||
position = ((v1 & 0xffffff) + depth - (v2 & 0xffffff)) % depth;
|
|
||||||
new_queue.m_v2 = (v2 & 0xff000000) | ((v2 & 0xffffff) - 1);
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prx: (sync), memcpy(buffer_addr, position * m_size + m_addr, m_size)
|
// prx: (sync), memcpy(buffer_addr, position * m_size + m_addr, m_size)
|
||||||
memcpy(buffer.get_ptr(), &queue->m_buffer[position * size], size);
|
memcpy(buffer.get_ptr(), &queue->m_buffer[position * size], size);
|
||||||
|
|
||||||
// prx: atomically insert 0 in first u8
|
// prx: atomically insert 0 in first u8
|
||||||
while (true)
|
queue->data &= { be_t<u32>::make(0xffffff), be_t<u32>::make(~0) };
|
||||||
{
|
|
||||||
const u64 old_data = queue->m_data();
|
|
||||||
CellSyncQueue new_queue;
|
|
||||||
new_queue.m_data() = old_data;
|
|
||||||
|
|
||||||
new_queue.m_v1 &= 0xffffff; // TODO: use InterlockedAnd() or something
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,39 +649,33 @@ s32 cellSyncQueueTryPop(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
|
|||||||
|
|
||||||
const u32 size = (u32)queue->m_size;
|
const u32 size = (u32)queue->m_size;
|
||||||
const u32 depth = (u32)queue->m_depth;
|
const u32 depth = (u32)queue->m_depth;
|
||||||
assert(((u32)queue->m_v1 & 0xffffff) <= depth && ((u32)queue->m_v2 & 0xffffff) <= depth);
|
assert(((u32)queue->data.read_relaxed().m_v1 & 0xffffff) <= depth && ((u32)queue->data.read_relaxed().m_v2 & 0xffffff) <= depth);
|
||||||
|
|
||||||
u32 position;
|
u32 position;
|
||||||
while (true)
|
if (s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
return syncQueueTryPopOp(queue, depth, position);
|
||||||
CellSyncQueue new_queue;
|
}))
|
||||||
new_queue.m_data() = old_data;
|
{
|
||||||
|
return res;
|
||||||
const u32 v1 = (u32)new_queue.m_v1;
|
|
||||||
const u32 v2 = (u32)new_queue.m_v2;
|
|
||||||
if ((v1 >> 24) || ((v2 & 0xffffff) <= (v2 >> 24)))
|
|
||||||
{
|
|
||||||
return CELL_SYNC_ERROR_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_queue.m_v1 = 0x1000000 | v1;
|
|
||||||
position = ((v1 & 0xffffff) + depth - (v2 & 0xffffff)) % depth;
|
|
||||||
new_queue.m_v2 = (v2 & 0xff000000) | ((v2 & 0xffffff) - 1);
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer.get_ptr(), &queue->m_buffer[position * size], size);
|
memcpy(buffer.get_ptr(), &queue->m_buffer[position * size], size);
|
||||||
|
queue->data &= { be_t<u32>::make(0xffffff), be_t<u32>::make(~0) };
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
while (true)
|
s32 syncQueueTryPeekOp(CellSyncQueue::data_t& queue, u32 depth, u32& position)
|
||||||
|
{
|
||||||
|
const u32 v1 = (u32)queue.m_v1;
|
||||||
|
const u32 v2 = (u32)queue.m_v2;
|
||||||
|
if ((v1 >> 24) || ((v2 & 0xffffff) <= (v2 >> 24)))
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
return CELL_SYNC_ERROR_BUSY;
|
||||||
CellSyncQueue new_queue;
|
|
||||||
new_queue.m_data() = old_data;
|
|
||||||
|
|
||||||
new_queue.m_v1 &= 0xffffff; // TODO: use InterlockedAnd() or something
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queue.m_v1 = 0x1000000 | v1;
|
||||||
|
position = ((v1 & 0xffffff) + depth - (v2 & 0xffffff)) % depth;
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,44 +694,24 @@ s32 cellSyncQueuePeek(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
|
|||||||
|
|
||||||
const u32 size = (u32)queue->m_size;
|
const u32 size = (u32)queue->m_size;
|
||||||
const u32 depth = (u32)queue->m_depth;
|
const u32 depth = (u32)queue->m_depth;
|
||||||
assert(((u32)queue->m_v1 & 0xffffff) <= depth && ((u32)queue->m_v2 & 0xffffff) <= depth);
|
assert(((u32)queue->data.read_relaxed().m_v1 & 0xffffff) <= depth && ((u32)queue->data.read_relaxed().m_v2 & 0xffffff) <= depth);
|
||||||
|
|
||||||
u32 position;
|
u32 position;
|
||||||
while (true)
|
while (queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
return syncQueueTryPeekOp(queue, depth, position);
|
||||||
CellSyncQueue new_queue;
|
}))
|
||||||
new_queue.m_data() = old_data;
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||||
const u32 v1 = (u32)new_queue.m_v1;
|
if (Emu.IsStopped())
|
||||||
const u32 v2 = (u32)new_queue.m_v2;
|
|
||||||
if ((v1 >> 24) || ((v2 & 0xffffff) <= (v2 >> 24)))
|
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
cellSync->Warning("cellSyncQueuePeek(queue_addr=0x%x) aborted", queue.addr());
|
||||||
if (Emu.IsStopped())
|
return CELL_OK;
|
||||||
{
|
|
||||||
cellSync->Warning("cellSyncQueuePeek(queue_addr=0x%x) aborted", queue.addr());
|
|
||||||
return CELL_OK;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new_queue.m_v1 = 0x1000000 | v1;
|
|
||||||
position = ((v1 & 0xffffff) + depth - (v2 & 0xffffff)) % depth;
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer.get_ptr(), &queue->m_buffer[position * size], size);
|
memcpy(buffer.get_ptr(), &queue->m_buffer[position * size], size);
|
||||||
|
queue->data &= { be_t<u32>::make(0xffffff), be_t<u32>::make(~0) };
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
const u64 old_data = queue->m_data();
|
|
||||||
CellSyncQueue new_queue;
|
|
||||||
new_queue.m_data() = old_data;
|
|
||||||
|
|
||||||
new_queue.m_v1 &= 0xffffff; // TODO: use InterlockedAnd() or something
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,38 +730,19 @@ s32 cellSyncQueueTryPeek(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
|
|||||||
|
|
||||||
const u32 size = (u32)queue->m_size;
|
const u32 size = (u32)queue->m_size;
|
||||||
const u32 depth = (u32)queue->m_depth;
|
const u32 depth = (u32)queue->m_depth;
|
||||||
assert(((u32)queue->m_v1 & 0xffffff) <= depth && ((u32)queue->m_v2 & 0xffffff) <= depth);
|
assert(((u32)queue->data.read_relaxed().m_v1 & 0xffffff) <= depth && ((u32)queue->data.read_relaxed().m_v2 & 0xffffff) <= depth);
|
||||||
|
|
||||||
u32 position;
|
u32 position;
|
||||||
while (true)
|
if (s32 res = queue->data.atomic_op(CELL_OK, [depth, &position](CellSyncQueue::data_t& queue) -> s32
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
return syncQueueTryPeekOp(queue, depth, position);
|
||||||
CellSyncQueue new_queue;
|
}))
|
||||||
new_queue.m_data() = old_data;
|
{
|
||||||
|
return res;
|
||||||
const u32 v1 = (u32)new_queue.m_v1;
|
|
||||||
const u32 v2 = (u32)new_queue.m_v2;
|
|
||||||
if ((v1 >> 24) || ((v2 & 0xffffff) <= (v2 >> 24)))
|
|
||||||
{
|
|
||||||
return CELL_SYNC_ERROR_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_queue.m_v1 = 0x1000000 | v1;
|
|
||||||
position = ((v1 & 0xffffff) + depth - (v2 & 0xffffff)) % depth;
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer.get_ptr(), &queue->m_buffer[position * size], size);
|
memcpy(buffer.get_ptr(), &queue->m_buffer[position * size], size);
|
||||||
|
queue->data &= { be_t<u32>::make(0xffffff), be_t<u32>::make(~0) };
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
const u64 old_data = queue->m_data();
|
|
||||||
CellSyncQueue new_queue;
|
|
||||||
new_queue.m_data() = old_data;
|
|
||||||
|
|
||||||
new_queue.m_v1 &= 0xffffff; // TODO: use InterlockedAnd() or something
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,9 +759,9 @@ s32 cellSyncQueueSize(vm::ptr<CellSyncQueue> queue)
|
|||||||
return CELL_SYNC_ERROR_ALIGN;
|
return CELL_SYNC_ERROR_ALIGN;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 count = (u32)queue->m_v2 & 0xffffff;
|
const u32 count = (u32)queue->data.read_relaxed().m_v2 & 0xffffff;
|
||||||
const u32 depth = (u32)queue->m_depth;
|
const u32 depth = (u32)queue->m_depth;
|
||||||
assert(((u32)queue->m_v1 & 0xffffff) <= depth && count <= depth);
|
assert(((u32)queue->data.read_relaxed().m_v1 & 0xffffff) <= depth && count <= depth);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@ -856,55 +780,50 @@ s32 cellSyncQueueClear(vm::ptr<CellSyncQueue> queue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const u32 depth = (u32)queue->m_depth;
|
const u32 depth = (u32)queue->m_depth;
|
||||||
assert(((u32)queue->m_v1 & 0xffffff) <= depth && ((u32)queue->m_v2 & 0xffffff) <= depth);
|
assert(((u32)queue->data.read_relaxed().m_v1 & 0xffffff) <= depth && ((u32)queue->data.read_relaxed().m_v2 & 0xffffff) <= depth);
|
||||||
|
|
||||||
// TODO: optimize if possible
|
// TODO: optimize if possible
|
||||||
while (true)
|
while (queue->data.atomic_op(CELL_OK, [depth](CellSyncQueue::data_t& queue) -> s32
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
const u32 v1 = (u32)queue.m_v1;
|
||||||
CellSyncQueue new_queue;
|
|
||||||
new_queue.m_data() = old_data;
|
|
||||||
|
|
||||||
const u32 v1 = (u32)new_queue.m_v1;
|
|
||||||
// prx: extract first u8, repeat if not zero, insert 1
|
// prx: extract first u8, repeat if not zero, insert 1
|
||||||
if (v1 >> 24)
|
if (v1 >> 24)
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
return CELL_SYNC_ERROR_BUSY;
|
||||||
if (Emu.IsStopped())
|
}
|
||||||
{
|
queue.m_v1 = v1 | 0x1000000;
|
||||||
cellSync->Warning("cellSyncQueueClear(queue_addr=0x%x) aborted (I)", queue.addr());
|
return CELL_OK;
|
||||||
return CELL_OK;
|
}))
|
||||||
}
|
{
|
||||||
continue;
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
cellSync->Warning("cellSyncQueueClear(queue_addr=0x%x) aborted (I)", queue.addr());
|
||||||
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
new_queue.m_v1 = v1 | 0x1000000;
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (queue->data.atomic_op(CELL_OK, [depth](CellSyncQueue::data_t& queue) -> s32
|
||||||
{
|
{
|
||||||
const u64 old_data = queue->m_data();
|
const u32 v2 = (u32)queue.m_v2;
|
||||||
CellSyncQueue new_queue;
|
|
||||||
new_queue.m_data() = old_data;
|
|
||||||
|
|
||||||
const u32 v2 = (u32)new_queue.m_v2;
|
|
||||||
// prx: extract 5th u8, repeat if not zero, insert 1
|
// prx: extract 5th u8, repeat if not zero, insert 1
|
||||||
if (v2 >> 24)
|
if (v2 >> 24)
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
return CELL_SYNC_ERROR_BUSY;
|
||||||
if (Emu.IsStopped())
|
}
|
||||||
{
|
queue.m_v2 = v2 | 0x1000000;
|
||||||
cellSync->Warning("cellSyncQueueClear(queue_addr=0x%x) aborted (II)", queue.addr());
|
return CELL_OK;
|
||||||
return CELL_OK;
|
}))
|
||||||
}
|
{
|
||||||
continue;
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
|
||||||
|
if (Emu.IsStopped())
|
||||||
|
{
|
||||||
|
cellSync->Warning("cellSyncQueueClear(queue_addr=0x%x) aborted (II)", queue.addr());
|
||||||
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
new_queue.m_v2 = v2 | 0x1000000;
|
|
||||||
if (InterlockedCompareExchange(&queue->m_data(), new_queue.m_data(), old_data) == old_data) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue->m_data() = 0;
|
queue->data.exchange({});
|
||||||
InterlockedCompareExchange(&queue->m_data(), 0, 0);
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -921,28 +840,18 @@ void syncLFQueueDump(vm::ptr<CellSyncLFQueue> queue)
|
|||||||
|
|
||||||
void syncLFQueueInit(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u8> buffer, u32 size, u32 depth, CellSyncQueueDirection direction, vm::ptr<void> eaSignal)
|
void syncLFQueueInit(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u8> buffer, u32 size, u32 depth, CellSyncQueueDirection direction, vm::ptr<void> eaSignal)
|
||||||
{
|
{
|
||||||
queue->m_h1 = 0;
|
|
||||||
queue->m_h2 = 0;
|
|
||||||
queue->m_h4 = 0;
|
|
||||||
queue->m_h5 = 0;
|
|
||||||
queue->m_h6 = 0;
|
|
||||||
queue->m_h8 = 0;
|
|
||||||
queue->m_size = size;
|
queue->m_size = size;
|
||||||
queue->m_depth = depth;
|
queue->m_depth = depth;
|
||||||
queue->m_buffer = buffer;
|
queue->m_buffer = buffer;
|
||||||
queue->m_direction = direction;
|
queue->m_direction = direction;
|
||||||
for (u32 i = 0; i < sizeof(queue->m_hs) / sizeof(queue->m_hs[0]); i++)
|
*queue->m_hs = {};
|
||||||
{
|
|
||||||
queue->m_hs[i] = 0;
|
|
||||||
}
|
|
||||||
queue->m_eaSignal = eaSignal;
|
queue->m_eaSignal = eaSignal;
|
||||||
|
|
||||||
if (direction == CELL_SYNC_QUEUE_ANY2ANY)
|
if (direction == CELL_SYNC_QUEUE_ANY2ANY)
|
||||||
{
|
{
|
||||||
queue->m_h3 = 0;
|
queue->pop1.write_relaxed({});
|
||||||
queue->m_h7 = 0;
|
queue->push1.write_relaxed({});
|
||||||
queue->m_buffer = buffer + 1;
|
queue->m_buffer.set(queue->m_buffer.addr() | be_t<u64>::make(1));
|
||||||
assert(queue->m_buffer.addr() % 2);
|
|
||||||
queue->m_bs[0] = -1;
|
queue->m_bs[0] = -1;
|
||||||
queue->m_bs[1] = -1;
|
queue->m_bs[1] = -1;
|
||||||
//m_bs[2]
|
//m_bs[2]
|
||||||
@ -955,8 +864,8 @@ void syncLFQueueInit(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u8> buffer, u32 siz
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//m_h3
|
queue->pop1.write_relaxed({ be_t<u16>::make(0), be_t<u16>::make(0), queue->pop1.read_relaxed().m_h3, be_t<u16>::make(0) });
|
||||||
//m_h7
|
queue->push1.write_relaxed({ be_t<u16>::make(0), be_t<u16>::make(0), queue->push1.read_relaxed().m_h7, be_t<u16>::make(0) });
|
||||||
queue->m_bs[0] = -1; // written as u32
|
queue->m_bs[0] = -1; // written as u32
|
||||||
queue->m_bs[1] = -1;
|
queue->m_bs[1] = -1;
|
||||||
queue->m_bs[2] = -1;
|
queue->m_bs[2] = -1;
|
||||||
|
@ -78,18 +78,11 @@ struct CellSyncQueue
|
|||||||
be_t<u32> m_v2;
|
be_t<u32> m_v2;
|
||||||
};
|
};
|
||||||
|
|
||||||
be_t<u32> m_v1;
|
vm::atomic<data_t> data;
|
||||||
be_t<u32> m_v2;
|
|
||||||
//vm::atomic<data_t> data;
|
|
||||||
be_t<u32> m_size;
|
be_t<u32> m_size;
|
||||||
be_t<u32> m_depth;
|
be_t<u32> m_depth;
|
||||||
vm::bptr<u8, 1, u64> m_buffer;
|
vm::bptr<u8, 1, u64> m_buffer;
|
||||||
be_t<u64> reserved;
|
be_t<u64> reserved;
|
||||||
|
|
||||||
volatile u64& m_data()
|
|
||||||
{
|
|
||||||
return *reinterpret_cast<u64*>(this);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(CellSyncQueue) == 32, "CellSyncQueue: wrong size");
|
static_assert(sizeof(CellSyncQueue) == 32, "CellSyncQueue: wrong size");
|
||||||
@ -104,21 +97,54 @@ enum CellSyncQueueDirection : u32 // CellSyncLFQueueDirection
|
|||||||
|
|
||||||
struct CellSyncLFQueue
|
struct CellSyncLFQueue
|
||||||
{
|
{
|
||||||
be_t<u16> m_h1; // 0x0
|
struct init_t
|
||||||
be_t<u16> m_h2; // 0x2
|
{
|
||||||
be_t<u16> m_h3; // 0x4
|
be_t<u32> m_sync;
|
||||||
be_t<u16> m_h4; // 0x6
|
};
|
||||||
be_t<u16> m_h5; // 0x8
|
|
||||||
be_t<u16> m_h6; // 0xA
|
struct pop1_t
|
||||||
be_t<u16> m_h7; // 0xC
|
{
|
||||||
be_t<u16> m_h8; // 0xE
|
be_t<u16> m_h1;
|
||||||
|
be_t<u16> m_h2;
|
||||||
|
be_t<u16> m_h3;
|
||||||
|
be_t<u16> m_h4;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct push1_t
|
||||||
|
{
|
||||||
|
be_t<u16> m_h5;
|
||||||
|
be_t<u16> m_h6;
|
||||||
|
be_t<u16> m_h7;
|
||||||
|
be_t<u16> m_h8;
|
||||||
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
vm::atomic<pop1_t> pop1;
|
||||||
|
vm::atomic<push1_t> push1;
|
||||||
|
};
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
be_t<u16> m_h1; // 0x0
|
||||||
|
be_t<u16> m_h2; // 0x2
|
||||||
|
be_t<u16> m_h3; // 0x4
|
||||||
|
be_t<u16> m_h4; // 0x6
|
||||||
|
be_t<u16> m_h5; // 0x8
|
||||||
|
be_t<u16> m_h6; // 0xA
|
||||||
|
be_t<u16> m_h7; // 0xC
|
||||||
|
be_t<u16> m_h8; // 0xE
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
be_t<u32> m_size; // 0x10
|
be_t<u32> m_size; // 0x10
|
||||||
be_t<u32> m_depth; // 0x14
|
be_t<u32> m_depth; // 0x14
|
||||||
vm::bptr<u8, 1, u64> m_buffer; // 0x18
|
vm::bptr<u8, 1, u64> m_buffer; // 0x18
|
||||||
u8 m_bs[4]; // 0x20
|
u8 m_bs[4]; // 0x20
|
||||||
be_t<CellSyncQueueDirection> m_direction; // 0x24
|
be_t<CellSyncQueueDirection> m_direction; // 0x24
|
||||||
be_t<u32> m_v1; // 0x28
|
be_t<u32> m_v1; // 0x28
|
||||||
be_t<u32> m_sync; // 0x2C
|
vm::atomic<init_t> init; // 0x2C
|
||||||
be_t<u16> m_hs[32]; // 0x30
|
be_t<u16> m_hs[32]; // 0x30
|
||||||
vm::bptr<void, 1, u64> m_eaSignal; // 0x70
|
vm::bptr<void, 1, u64> m_eaSignal; // 0x70
|
||||||
be_t<u32> m_v2; // 0x78
|
be_t<u32> m_v2; // 0x78
|
||||||
|
Loading…
x
Reference in New Issue
Block a user