Vortex 2.0 changes:
+ Microarchitecture optimizations + 64-bit support + Xilinx FPGA support + LLVM-16 support + Refactoring and quality control fixes minor update minor update minor update minor update minor update minor update cleanup cleanup cache bindings and memory perf refactory minor update minor update hw unit tests fixes minor update minor update minor update minor update minor update minor udpate minor update minor update minor update minor update minor update minor update minor update minor updates minor updates minor update minor update minor update minor update minor update minor update minor updates minor updates minor updates minor updates minor update minor update
This commit is contained in:
@@ -1,7 +1,19 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
constexpr uint32_t count_leading_zeros(uint32_t value) {
|
||||
@@ -77,5 +89,15 @@ T sext(const T& word, uint32_t width) {
|
||||
if (width == (sizeof(T) * 8))
|
||||
return word;
|
||||
T mask((static_cast<T>(1) << width) - 1);
|
||||
return ((word >> (width - 1)) & 0x1) ? (word | ~mask) : word;
|
||||
}
|
||||
return ((word >> (width - 1)) & 0x1) ? (word | ~mask) : (word & mask);
|
||||
}
|
||||
|
||||
template <typename T = uint32_t>
|
||||
T zext(const T& word, uint32_t width) {
|
||||
assert(width > 1);
|
||||
assert(width <= (sizeof(T) * 8));
|
||||
if (width == (sizeof(T) * 8))
|
||||
return word;
|
||||
T mask((static_cast<T>(1) << width) - 1);
|
||||
return word & mask;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "mem.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
@@ -20,8 +33,9 @@ RamMemDevice::RamMemDevice(const char *filename, uint32_t wordSize)
|
||||
contents_.push_back(input.get());
|
||||
} while (input);
|
||||
|
||||
while (contents_.size() & (wordSize-1))
|
||||
while (contents_.size() & (wordSize-1)) {
|
||||
contents_.push_back(0x00);
|
||||
}
|
||||
}
|
||||
|
||||
RamMemDevice::RamMemDevice(uint64_t size, uint32_t wordSize)
|
||||
@@ -29,7 +43,7 @@ RamMemDevice::RamMemDevice(uint64_t size, uint32_t wordSize)
|
||||
, wordSize_(wordSize)
|
||||
{}
|
||||
|
||||
void RamMemDevice::read(void *data, uint64_t addr, uint64_t size) {
|
||||
void RamMemDevice::read(void* data, uint64_t addr, uint64_t size) {
|
||||
auto addr_end = addr + size;
|
||||
if ((addr & (wordSize_-1))
|
||||
|| (addr_end & (wordSize_-1))
|
||||
@@ -44,7 +58,7 @@ void RamMemDevice::read(void *data, uint64_t addr, uint64_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
void RamMemDevice::write(const void *data, uint64_t addr, uint64_t size) {
|
||||
void RamMemDevice::write(const void* data, uint64_t addr, uint64_t size) {
|
||||
auto addr_end = addr + size;
|
||||
if ((addr & (wordSize_-1))
|
||||
|| (addr_end & (wordSize_-1))
|
||||
@@ -68,26 +82,26 @@ void RomMemDevice::write(const void* /*data*/, uint64_t /*addr*/, uint64_t /*siz
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool MemoryUnit::ADecoder::lookup(uint64_t a, uint32_t wordSize, mem_accessor_t* ma) {
|
||||
uint64_t e = a + (wordSize - 1);
|
||||
assert(e >= a);
|
||||
bool MemoryUnit::ADecoder::lookup(uint64_t addr, uint32_t wordSize, mem_accessor_t* ma) {
|
||||
uint64_t end = addr + (wordSize - 1);
|
||||
assert(end >= addr);
|
||||
for (auto iter = entries_.rbegin(), iterE = entries_.rend(); iter != iterE; ++iter) {
|
||||
if (a >= iter->start && e <= iter->end) {
|
||||
if (addr >= iter->start && end <= iter->end) {
|
||||
ma->md = iter->md;
|
||||
ma->addr = a - iter->start;
|
||||
ma->addr = addr - iter->start;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MemoryUnit::ADecoder::map(uint64_t a, uint64_t e, MemDevice &m) {
|
||||
assert(e >= a);
|
||||
entry_t entry{&m, a, e};
|
||||
void MemoryUnit::ADecoder::map(uint64_t start, uint64_t end, MemDevice &md) {
|
||||
assert(end >= start);
|
||||
entry_t entry{&md, start, end};
|
||||
entries_.emplace_back(entry);
|
||||
}
|
||||
|
||||
void MemoryUnit::ADecoder::read(void *data, uint64_t addr, uint64_t size) {
|
||||
void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) {
|
||||
mem_accessor_t ma;
|
||||
if (!this->lookup(addr, size, &ma)) {
|
||||
std::cout << "lookup of 0x" << std::hex << addr << " failed.\n";
|
||||
@@ -96,7 +110,7 @@ void MemoryUnit::ADecoder::read(void *data, uint64_t addr, uint64_t size) {
|
||||
ma.md->read(data, ma.addr, size);
|
||||
}
|
||||
|
||||
void MemoryUnit::ADecoder::write(const void *data, uint64_t addr, uint64_t size) {
|
||||
void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) {
|
||||
mem_accessor_t ma;
|
||||
if (!this->lookup(addr, size, &ma)) {
|
||||
std::cout << "lookup of 0x" << std::hex << addr << " failed.\n";
|
||||
@@ -107,11 +121,11 @@ void MemoryUnit::ADecoder::write(const void *data, uint64_t addr, uint64_t size)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MemoryUnit::MemoryUnit(uint64_t pageSize, uint64_t addrBytes, bool disableVm)
|
||||
MemoryUnit::MemoryUnit(uint64_t pageSize)
|
||||
: pageSize_(pageSize)
|
||||
, addrBytes_(addrBytes)
|
||||
, disableVM_(disableVm) {
|
||||
if (!disableVm) {
|
||||
, enableVM_(pageSize != 0)
|
||||
, amo_reservation_({0x0, false}) {
|
||||
if (pageSize != 0) {
|
||||
tlb_[0] = TLBEntry(0, 077);
|
||||
}
|
||||
}
|
||||
@@ -133,30 +147,38 @@ MemoryUnit::TLBEntry MemoryUnit::tlbLookup(uint64_t vAddr, uint32_t flagMask) {
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryUnit::read(void *data, uint64_t addr, uint64_t size, bool sup) {
|
||||
uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) {
|
||||
uint64_t pAddr;
|
||||
if (disableVM_) {
|
||||
pAddr = addr;
|
||||
} else {
|
||||
uint32_t flagMask = sup ? 8 : 1;
|
||||
if (enableVM_) {
|
||||
TLBEntry t = this->tlbLookup(addr, flagMask);
|
||||
pAddr = t.pfn * pageSize_ + addr % pageSize_;
|
||||
} else {
|
||||
pAddr = addr;
|
||||
}
|
||||
return pAddr;
|
||||
}
|
||||
|
||||
void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup) {
|
||||
uint64_t pAddr = this->toPhyAddr(addr, sup ? 8 : 1);
|
||||
return decoder_.read(data, pAddr, size);
|
||||
}
|
||||
|
||||
void MemoryUnit::write(const void *data, uint64_t addr, uint64_t size, bool sup) {
|
||||
uint64_t pAddr;
|
||||
if (disableVM_) {
|
||||
pAddr = addr;
|
||||
} else {
|
||||
uint32_t flagMask = sup ? 16 : 2;
|
||||
TLBEntry t = tlbLookup(addr, flagMask);
|
||||
pAddr = t.pfn * pageSize_ + addr % pageSize_;
|
||||
}
|
||||
void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup) {
|
||||
uint64_t pAddr = this->toPhyAddr(addr, sup ? 16 : 1);
|
||||
decoder_.write(data, pAddr, size);
|
||||
amo_reservation_.valid = false;
|
||||
}
|
||||
|
||||
void MemoryUnit::amo_reserve(uint64_t addr) {
|
||||
uint64_t pAddr = this->toPhyAddr(addr, 1);
|
||||
amo_reservation_.addr = pAddr;
|
||||
amo_reservation_.valid = true;
|
||||
}
|
||||
|
||||
bool MemoryUnit::amo_check(uint64_t addr) {
|
||||
uint64_t pAddr = this->toPhyAddr(addr, 1);
|
||||
return amo_reservation_.valid && (amo_reservation_.addr == pAddr);
|
||||
}
|
||||
void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) {
|
||||
tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags);
|
||||
}
|
||||
@@ -168,12 +190,14 @@ void MemoryUnit::tlbRm(uint64_t va) {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RAM::RAM(uint32_t page_size)
|
||||
: size_(0)
|
||||
RAM::RAM(uint32_t page_size, uint64_t capacity)
|
||||
: capacity_(capacity)
|
||||
, page_bits_(log2ceil(page_size))
|
||||
, last_page_(nullptr)
|
||||
, last_page_index_(0) {
|
||||
assert(ispow2(page_size));
|
||||
assert(0 == capacity || ispow2(capacity));
|
||||
assert(0 == (capacity % page_size));
|
||||
}
|
||||
|
||||
RAM::~RAM() {
|
||||
@@ -191,6 +215,9 @@ uint64_t RAM::size() const {
|
||||
}
|
||||
|
||||
uint8_t *RAM::get(uint64_t address) const {
|
||||
if (capacity_ != 0 && address >= capacity_) {
|
||||
throw OutOfRange();
|
||||
}
|
||||
uint32_t page_size = 1 << page_bits_;
|
||||
uint32_t page_offset = address & (page_size - 1);
|
||||
uint64_t page_index = address >> page_bits_;
|
||||
@@ -218,14 +245,14 @@ uint8_t *RAM::get(uint64_t address) const {
|
||||
return page + page_offset;
|
||||
}
|
||||
|
||||
void RAM::read(void *data, uint64_t addr, uint64_t size) {
|
||||
void RAM::read(void* data, uint64_t addr, uint64_t size) {
|
||||
uint8_t* d = (uint8_t*)data;
|
||||
for (uint64_t i = 0; i < size; i++) {
|
||||
d[i] = *this->get(addr + i);
|
||||
}
|
||||
}
|
||||
|
||||
void RAM::write(const void *data, uint64_t addr, uint64_t size) {
|
||||
void RAM::write(const void* data, uint64_t addr, uint64_t size) {
|
||||
const uint8_t* d = (const uint8_t*)data;
|
||||
for (uint64_t i = 0; i < size; i++) {
|
||||
*this->get(addr + i) = d[i];
|
||||
@@ -236,6 +263,7 @@ void RAM::loadBinImage(const char* filename, uint64_t destination) {
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs) {
|
||||
std::cout << "error: " << filename << " not found" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
ifs.seekg(0, ifs.end);
|
||||
@@ -268,6 +296,7 @@ void RAM::loadHexImage(const char* filename) {
|
||||
std::ifstream ifs(filename);
|
||||
if (!ifs) {
|
||||
std::cout << "error: " << filename << " not found" << std::endl;
|
||||
std::abort();
|
||||
}
|
||||
|
||||
ifs.seekg(0, ifs.end);
|
||||
@@ -313,4 +342,4 @@ void RAM::loadHexImage(const char* filename) {
|
||||
++line;
|
||||
--size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
@@ -7,13 +20,14 @@
|
||||
|
||||
namespace vortex {
|
||||
struct BadAddress {};
|
||||
struct OutOfRange {};
|
||||
|
||||
class MemDevice {
|
||||
public:
|
||||
virtual ~MemDevice() {}
|
||||
virtual uint64_t size() const = 0;
|
||||
virtual void read(void *data, uint64_t addr, uint64_t size) = 0;
|
||||
virtual void write(const void *data, uint64_t addr, uint64_t size) = 0;
|
||||
virtual void read(void* data, uint64_t addr, uint64_t size) = 0;
|
||||
virtual void write(const void* data, uint64_t addr, uint64_t size) = 0;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -21,11 +35,11 @@ public:
|
||||
class RamMemDevice : public MemDevice {
|
||||
public:
|
||||
RamMemDevice(uint64_t size, uint32_t wordSize);
|
||||
RamMemDevice(const char *filename, uint32_t wordSize);
|
||||
RamMemDevice(const char* filename, uint32_t wordSize);
|
||||
~RamMemDevice() {}
|
||||
|
||||
void read(void *data, uint64_t addr, uint64_t size) override;
|
||||
void write(const void *data, uint64_t addr, uint64_t size) override;
|
||||
void read(void* data, uint64_t addr, uint64_t size) override;
|
||||
void write(const void* data, uint64_t addr, uint64_t size) override;
|
||||
|
||||
virtual uint64_t size() const {
|
||||
return contents_.size();
|
||||
@@ -50,7 +64,7 @@ public:
|
||||
|
||||
~RomMemDevice();
|
||||
|
||||
void write(const void *data, uint64_t addr, uint64_t size) override;
|
||||
void write(const void* data, uint64_t addr, uint64_t size) override;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -63,47 +77,56 @@ public:
|
||||
: faultAddr(a)
|
||||
, notFound(nf)
|
||||
{}
|
||||
uint64_t faultAddr;
|
||||
bool notFound;
|
||||
uint64_t faultAddr;
|
||||
bool notFound;
|
||||
};
|
||||
|
||||
MemoryUnit(uint64_t pageSize, uint64_t addrBytes, bool disableVm = false);
|
||||
MemoryUnit(uint64_t pageSize = 0);
|
||||
|
||||
void attach(MemDevice &m, uint64_t start, uint64_t end);
|
||||
|
||||
void read(void *data, uint64_t addr, uint64_t size, bool sup);
|
||||
void write(const void *data, uint64_t addr, uint64_t size, bool sup);
|
||||
void read(void* data, uint64_t addr, uint64_t size, bool sup);
|
||||
void write(const void* data, uint64_t addr, uint64_t size, bool sup);
|
||||
|
||||
void amo_reserve(uint64_t addr);
|
||||
bool amo_check(uint64_t addr);
|
||||
|
||||
void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags);
|
||||
void tlbRm(uint64_t va);
|
||||
void tlbRm(uint64_t vaddr);
|
||||
void tlbFlush() {
|
||||
tlb_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct amo_reservation_t {
|
||||
uint64_t addr;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
class ADecoder {
|
||||
public:
|
||||
ADecoder() {}
|
||||
|
||||
void read(void *data, uint64_t addr, uint64_t size);
|
||||
void write(const void *data, uint64_t addr, uint64_t size);
|
||||
void read(void* data, uint64_t addr, uint64_t size);
|
||||
void write(const void* data, uint64_t addr, uint64_t size);
|
||||
|
||||
void map(uint64_t start, uint64_t end, MemDevice &md);
|
||||
|
||||
private:
|
||||
|
||||
struct mem_accessor_t {
|
||||
MemDevice* md;
|
||||
uint64_t addr;
|
||||
MemDevice* md;
|
||||
uint64_t addr;
|
||||
};
|
||||
|
||||
struct entry_t {
|
||||
MemDevice *md;
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
MemDevice* md;
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
};
|
||||
|
||||
bool lookup(uint64_t a, uint32_t wordSize, mem_accessor_t*);
|
||||
bool lookup(uint64_t addr, uint32_t wordSize, mem_accessor_t*);
|
||||
|
||||
std::vector<entry_t> entries_;
|
||||
};
|
||||
@@ -120,11 +143,14 @@ private:
|
||||
|
||||
TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask);
|
||||
|
||||
uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask);
|
||||
|
||||
std::unordered_map<uint64_t, TLBEntry> tlb_;
|
||||
uint64_t pageSize_;
|
||||
uint64_t addrBytes_;
|
||||
ADecoder decoder_;
|
||||
bool disableVM_;
|
||||
uint64_t pageSize_;
|
||||
ADecoder decoder_;
|
||||
bool enableVM_;
|
||||
|
||||
amo_reservation_t amo_reservation_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -132,15 +158,15 @@ private:
|
||||
class RAM : public MemDevice {
|
||||
public:
|
||||
|
||||
RAM(uint32_t page_size);
|
||||
RAM(uint32_t page_size, uint64_t capacity = 0);
|
||||
~RAM();
|
||||
|
||||
void clear();
|
||||
|
||||
uint64_t size() const override;
|
||||
|
||||
void read(void *data, uint64_t addr, uint64_t size) override;
|
||||
void write(const void *data, uint64_t addr, uint64_t size) override;
|
||||
void read(void* data, uint64_t addr, uint64_t size) override;
|
||||
void write(const void* data, uint64_t addr, uint64_t size) override;
|
||||
|
||||
void loadBinImage(const char* filename, uint64_t destination);
|
||||
void loadHexImage(const char* filename);
|
||||
@@ -157,11 +183,11 @@ private:
|
||||
|
||||
uint8_t *get(uint64_t address) const;
|
||||
|
||||
uint64_t size_;
|
||||
uint64_t capacity_;
|
||||
uint32_t page_bits_;
|
||||
mutable std::unordered_map<uint64_t, uint8_t*> pages_;
|
||||
mutable uint8_t* last_page_;
|
||||
mutable uint64_t last_page_index_;
|
||||
};
|
||||
|
||||
} // namespace vortex
|
||||
} // namespace vortex
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stack>
|
||||
@@ -18,8 +31,9 @@ public:
|
||||
void* allocate() {
|
||||
void* mem;
|
||||
if (!free_list_.empty()) {
|
||||
mem = static_cast<void*>(free_list_.top());
|
||||
auto entry = free_list_.top();
|
||||
free_list_.pop();
|
||||
mem = static_cast<void*>(entry);
|
||||
} else {
|
||||
mem = ::operator new(sizeof(T));
|
||||
}
|
||||
@@ -36,12 +50,13 @@ public:
|
||||
|
||||
void flush() {
|
||||
while (!free_list_.empty()) {
|
||||
::operator delete(free_list_.top());
|
||||
auto entry = free_list_.top();
|
||||
free_list_.pop();
|
||||
::operator delete(entry);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::stack<void*> free_list_;
|
||||
std::stack<T*> free_list_;
|
||||
uint32_t max_size_;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rvfloats.h"
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -16,12 +29,9 @@ inline float64_t to_float64_t(uint64_t x) { return float64_t{x}; }
|
||||
inline uint32_t from_float32_t(float32_t x) { return uint32_t(x.v); }
|
||||
inline uint64_t from_float64_t(float64_t x) { return uint64_t(x.v); }
|
||||
|
||||
inline uint32_t get_fflags() {
|
||||
uint32_t fflags = softfloat_exceptionFlags;
|
||||
if (fflags) {
|
||||
softfloat_exceptionFlags = 0;
|
||||
}
|
||||
return fflags;
|
||||
inline void rv_init(uint32_t frm) {
|
||||
softfloat_exceptionFlags = 0;
|
||||
softfloat_roundingMode = frm;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -29,289 +39,296 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
uint32_t rv_fadd_s(uint32_t a, uint32_t b, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_add(to_float32_t(a), to_float32_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fadd_d(uint64_t a, uint64_t b, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_add(to_float64_t(a), to_float64_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_fsub_s(uint32_t a, uint32_t b, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_sub(to_float32_t(a), to_float32_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fsub_d(uint64_t a, uint64_t b, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_sub(to_float64_t(a), to_float64_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_fmul_s(uint32_t a, uint32_t b, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_mul(to_float32_t(a), to_float32_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fmul_d(uint64_t a, uint64_t b, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_mul(to_float64_t(a), to_float64_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_fmadd_s(uint32_t a, uint32_t b, uint32_t c, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_mulAdd(to_float32_t(a), to_float32_t(b), to_float32_t(c));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fmadd_d(uint64_t a, uint64_t b, uint64_t c, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_mulAdd(to_float64_t(a), to_float64_t(b), to_float64_t(c));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_fmsub_s(uint32_t a, uint32_t b, uint32_t c, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto c_neg = c ^ F32_SIGN;
|
||||
auto r = f32_mulAdd(to_float32_t(a), to_float32_t(b), to_float32_t(c_neg));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fmsub_d(uint64_t a, uint64_t b, uint64_t c, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto c_neg = c ^ F64_SIGN;
|
||||
auto r = f64_mulAdd(to_float64_t(a), to_float64_t(b), to_float64_t(c_neg));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_fnmadd_s(uint32_t a, uint32_t b, uint32_t c, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto a_neg = a ^ F32_SIGN;
|
||||
auto c_neg = c ^ F32_SIGN;
|
||||
auto r = f32_mulAdd(to_float32_t(a_neg), to_float32_t(b), to_float32_t(c_neg));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fnmadd_d(uint64_t a, uint64_t b, uint64_t c, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto a_neg = a ^ F64_SIGN;
|
||||
auto c_neg = c ^ F64_SIGN;
|
||||
auto r = f64_mulAdd(to_float64_t(a_neg), to_float64_t(b), to_float64_t(c_neg));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_fnmsub_s(uint32_t a, uint32_t b, uint32_t c, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto a_neg = a ^ F32_SIGN;
|
||||
auto r = f32_mulAdd(to_float32_t(a_neg), to_float32_t(b), to_float32_t(c));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fnmsub_d(uint64_t a, uint64_t b, uint64_t c, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto a_neg = a ^ F64_SIGN;
|
||||
auto r = f64_mulAdd(to_float64_t(a_neg), to_float64_t(b), to_float64_t(c));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_fdiv_s(uint32_t a, uint32_t b, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_div(to_float32_t(a), to_float32_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fdiv_d(uint64_t a, uint64_t b, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_div(to_float64_t(a), to_float64_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_fsqrt_s(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_sqrt(to_float32_t(a));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_fsqrt_d(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_sqrt(to_float64_t(a));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_ftoi_s(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_to_i32(to_float32_t(a), frm, true);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t rv_ftoi_d(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_to_i32(to_float64_t(a), frm, true);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t rv_ftou_s(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_to_ui32(to_float32_t(a), frm, true);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t rv_ftou_d(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_to_ui32(to_float64_t(a), frm, true);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t rv_ftol_s(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_to_i64(to_float32_t(a), frm, true);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t rv_ftol_d(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_to_i64(to_float64_t(a), frm, true);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t rv_ftolu_s(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f32_to_ui64(to_float32_t(a), frm, true);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t rv_ftolu_d(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = f64_to_ui64(to_float64_t(a), frm, true);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t rv_itof_s(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = i32_to_f32(a);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_itof_d(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = i32_to_f64(a);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_utof_s(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = ui32_to_f32(a);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_utof_d(uint32_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = ui32_to_f64(a);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_ltof_s(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = i64_to_f32(a);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_ltof_d(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = i64_to_f64(a);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
uint32_t rv_lutof_s(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = ui64_to_f32(a);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float32_t(r);
|
||||
}
|
||||
|
||||
uint64_t rv_lutof_d(uint64_t a, uint32_t frm, uint32_t* fflags) {
|
||||
softfloat_roundingMode = frm;
|
||||
rv_init(frm);
|
||||
auto r = ui64_to_f64(a);
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return from_float64_t(r);
|
||||
}
|
||||
|
||||
bool rv_flt_s(uint32_t a, uint32_t b, uint32_t* fflags) {
|
||||
rv_init(0);
|
||||
auto r = f32_lt(to_float32_t(a), to_float32_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
bool rv_flt_d(uint64_t a, uint64_t b, uint32_t* fflags) {
|
||||
rv_init(0);
|
||||
auto r = f64_lt(to_float64_t(a), to_float64_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
bool rv_fle_s(uint32_t a, uint32_t b, uint32_t* fflags) {
|
||||
rv_init(0);
|
||||
auto r = f32_le(to_float32_t(a), to_float32_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
bool rv_fle_d(uint64_t a, uint64_t b, uint32_t* fflags) {
|
||||
rv_init(0);
|
||||
auto r = f64_le(to_float64_t(a), to_float64_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
bool rv_feq_s(uint32_t a, uint32_t b, uint32_t* fflags) {
|
||||
rv_init(0);
|
||||
auto r = f32_eq(to_float32_t(a), to_float32_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
bool rv_feq_d(uint64_t a, uint64_t b, uint32_t* fflags) {
|
||||
rv_init(0);
|
||||
auto r = f64_eq(to_float64_t(a), to_float64_t(b));
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t rv_fmin_s(uint32_t a, uint32_t b, uint32_t* fflags) {
|
||||
uint32_t r;
|
||||
rv_init(0);
|
||||
if (isNaNF32UI(a) && isNaNF32UI(b)) {
|
||||
r = defaultNaNF32UI;
|
||||
} else {
|
||||
@@ -324,12 +341,13 @@ uint32_t rv_fmin_s(uint32_t a, uint32_t b, uint32_t* fflags) {
|
||||
r = b;
|
||||
}
|
||||
}
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t rv_fmin_d(uint64_t a, uint64_t b, uint32_t* fflags) {
|
||||
uint64_t r;
|
||||
rv_init(0);
|
||||
if (isNaNF64UI(a) && isNaNF64UI(b)) {
|
||||
r = defaultNaNF64UI;
|
||||
} else {
|
||||
@@ -342,12 +360,13 @@ uint64_t rv_fmin_d(uint64_t a, uint64_t b, uint32_t* fflags) {
|
||||
r = b;
|
||||
}
|
||||
}
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint32_t rv_fmax_s(uint32_t a, uint32_t b, uint32_t* fflags) {
|
||||
uint32_t r;
|
||||
rv_init(0);
|
||||
if (isNaNF32UI(a) && isNaNF32UI(b)) {
|
||||
r = defaultNaNF32UI;
|
||||
} else {
|
||||
@@ -360,12 +379,13 @@ uint32_t rv_fmax_s(uint32_t a, uint32_t b, uint32_t* fflags) {
|
||||
r = b;
|
||||
}
|
||||
}
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
uint64_t rv_fmax_d(uint64_t a, uint64_t b, uint32_t* fflags) {
|
||||
uint64_t r;
|
||||
rv_init(0);
|
||||
if (isNaNF64UI(a) && isNaNF64UI(b)) {
|
||||
r = defaultNaNF64UI;
|
||||
} else {
|
||||
@@ -378,7 +398,7 @@ uint64_t rv_fmax_d(uint64_t a, uint64_t b, uint32_t* fflags) {
|
||||
r = b;
|
||||
}
|
||||
}
|
||||
if (fflags) { *fflags = get_fflags(); }
|
||||
if (fflags) { *fflags = softfloat_exceptionFlags; }
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
#ifndef RVFLOATS_H
|
||||
#define RVFLOATS_H
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -78,5 +90,3 @@ uint64_t rv_ftod(uint32_t a);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,16 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
@@ -84,33 +97,39 @@ public:
|
||||
}
|
||||
|
||||
uint64_t pop() {
|
||||
auto cycle = queue_.front().cycle;
|
||||
auto cycles = queue_.front().cycles;
|
||||
queue_.pop();
|
||||
return cycle;
|
||||
return cycles;
|
||||
}
|
||||
|
||||
void tx_callback(const TxCallback& callback) {
|
||||
tx_cb_ = callback;
|
||||
}
|
||||
|
||||
uint64_t arrival_time() const {
|
||||
if (queue_.empty())
|
||||
return 0;
|
||||
return queue_.front().cycles;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct timed_pkt_t {
|
||||
Pkt pkt;
|
||||
uint64_t cycle;
|
||||
uint64_t cycles;
|
||||
};
|
||||
|
||||
std::queue<timed_pkt_t> queue_;
|
||||
SimPort* peer_;
|
||||
TxCallback tx_cb_;
|
||||
|
||||
void push(const Pkt& data, uint64_t cycle) {
|
||||
void push(const Pkt& data, uint64_t cycles) {
|
||||
if (tx_cb_) {
|
||||
tx_cb_(data, cycle);
|
||||
tx_cb_(data, cycles);
|
||||
}
|
||||
if (peer_) {
|
||||
peer_->push(data, cycle);
|
||||
peer_->push(data, cycles);
|
||||
} else {
|
||||
queue_.push({data, cycle});
|
||||
queue_.push({data, cycles});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,14 +148,14 @@ public:
|
||||
|
||||
virtual void fire() const = 0;
|
||||
|
||||
uint64_t time() const {
|
||||
return time_;
|
||||
uint64_t cycles() const {
|
||||
return cycles_;
|
||||
}
|
||||
|
||||
protected:
|
||||
SimEventBase(uint64_t time) : time_(time) {}
|
||||
SimEventBase(uint64_t cycles) : cycles_(cycles) {}
|
||||
|
||||
uint64_t time_;
|
||||
uint64_t cycles_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -150,8 +169,8 @@ public:
|
||||
|
||||
typedef std::function<void (const Pkt&)> Func;
|
||||
|
||||
SimCallEvent(const Func& func, const Pkt& pkt, uint64_t time)
|
||||
: SimEventBase(time)
|
||||
SimCallEvent(const Func& func, const Pkt& pkt, uint64_t cycles)
|
||||
: SimEventBase(cycles)
|
||||
, func_(func)
|
||||
, pkt_(pkt)
|
||||
{}
|
||||
@@ -180,11 +199,11 @@ template <typename Pkt>
|
||||
class SimPortEvent : public SimEventBase {
|
||||
public:
|
||||
void fire() const override {
|
||||
const_cast<SimPort<Pkt>*>(port_)->push(pkt_, time_);
|
||||
const_cast<SimPort<Pkt>*>(port_)->push(pkt_, cycles_);
|
||||
}
|
||||
|
||||
SimPortEvent(const SimPort<Pkt>* port, const Pkt& pkt, uint64_t time)
|
||||
: SimEventBase(time)
|
||||
SimPortEvent(const SimPort<Pkt>* port, const Pkt& pkt, uint64_t cycles)
|
||||
: SimEventBase(cycles)
|
||||
, port_(port)
|
||||
, pkt_(pkt)
|
||||
{}
|
||||
@@ -330,7 +349,7 @@ public:
|
||||
auto evt_it_end = events_.end();
|
||||
while (evt_it != evt_it_end) {
|
||||
auto& event = *evt_it;
|
||||
if (cycles_ >= event->time()) {
|
||||
if (cycles_ >= event->cycles()) {
|
||||
event->fire();
|
||||
evt_it = events_.erase(evt_it);
|
||||
} else {
|
||||
@@ -395,5 +414,5 @@ void SimPort<Pkt>::send(const Pkt& pkt, uint64_t delay) const {
|
||||
reinterpret_cast<const SimPort<Pkt>*>(peer_)->send(pkt, delay);
|
||||
} else {
|
||||
SimPlatform::instance().schedule(this, pkt, delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
78
sim/common/stringutil.h
Normal file
78
sim/common/stringutil.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
class ByteStream : public std::istream {
|
||||
public:
|
||||
ByteStream(const void *buf, std::size_t size) : buf_(buf), size_(size) {}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const ByteStream& obj) {
|
||||
auto oldflags = os.flags();
|
||||
auto oldwidth = os.width();
|
||||
auto oldfill = os.fill();
|
||||
for (std::size_t i = 0, n = obj.size_; i < n; ++i) {
|
||||
int byte = *((uint8_t*)obj.buf_ + (n - 1 - i));
|
||||
os << std::hex << std::setw(2) << std::setfill('0') << byte;
|
||||
}
|
||||
os.fill(oldfill);
|
||||
os.width(oldwidth);
|
||||
os.flags(oldflags);
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
const void *buf_;
|
||||
std::size_t size_;
|
||||
};
|
||||
|
||||
class IndentStream : public std::streambuf {
|
||||
public:
|
||||
explicit IndentStream(std::streambuf* dest, int indent = 4)
|
||||
: dest_(dest)
|
||||
, isBeginLine_(true)
|
||||
, indent_(indent, ' ')
|
||||
, owner_(nullptr)
|
||||
{}
|
||||
|
||||
explicit IndentStream(std::ostream& dest, int indent = 4)
|
||||
: dest_(dest.rdbuf())
|
||||
, isBeginLine_(true)
|
||||
, indent_(indent, ' ')
|
||||
, owner_(&dest) {
|
||||
owner_->rdbuf(this);
|
||||
}
|
||||
|
||||
virtual ~IndentStream() {
|
||||
if (owner_)
|
||||
owner_->rdbuf(dest_);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int overflow(int ch) {
|
||||
if (isBeginLine_ && ch != '\n') {
|
||||
dest_->sputn(indent_.data(), indent_.size());
|
||||
}
|
||||
isBeginLine_ = ch == '\n';
|
||||
return dest_->sputc(ch);
|
||||
}
|
||||
|
||||
private:
|
||||
std::streambuf* dest_;
|
||||
bool isBeginLine_;
|
||||
std::string indent_;
|
||||
std::ostream* owner_;
|
||||
};
|
||||
@@ -1,237 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cocogfx/include/fixed.h>
|
||||
#include <bitmanip.h>
|
||||
|
||||
using namespace cocogfx;
|
||||
|
||||
enum class WrapMode {
|
||||
Clamp,
|
||||
Repeat,
|
||||
Mirror,
|
||||
};
|
||||
|
||||
enum class TexFormat {
|
||||
A8R8G8B8,
|
||||
R5G6B5,
|
||||
A1R5G5B5,
|
||||
A4R4G4B4,
|
||||
A8L8,
|
||||
L8,
|
||||
A8,
|
||||
};
|
||||
|
||||
template <uint32_t F, typename T = int32_t>
|
||||
T Clamp(Fixed<F,T> fx, WrapMode mode) {
|
||||
switch (mode) {
|
||||
case WrapMode::Clamp: return (fx.data() < 0) ? 0 : ((fx.data() > Fixed<F,T>::MASK) ? Fixed<F,T>::MASK : fx.data());
|
||||
case WrapMode::Repeat: return (fx.data() & Fixed<F,T>::MASK);
|
||||
case WrapMode::Mirror: return (bit_get(fx.data(), Fixed<F,T>::FRAC) ? ~fx.data() : fx.data());
|
||||
default:
|
||||
std::abort();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t Stride(TexFormat format) {
|
||||
switch (format) {
|
||||
case TexFormat::A8R8G8B8:
|
||||
return 4;
|
||||
case TexFormat::R5G6B5:
|
||||
case TexFormat::A1R5G5B5:
|
||||
case TexFormat::A4R4G4B4:
|
||||
case TexFormat::A8L8:
|
||||
return 2;
|
||||
case TexFormat::L8:
|
||||
case TexFormat::A8:
|
||||
return 1;
|
||||
default:
|
||||
std::abort();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Unpack8888(TexFormat format,
|
||||
uint32_t texel,
|
||||
uint32_t* lo,
|
||||
uint32_t* hi) {
|
||||
uint32_t r, g, b, a;
|
||||
switch (format) {
|
||||
case TexFormat::A8R8G8B8:
|
||||
r = (texel >> 16) & 0xff;
|
||||
g = (texel >> 8) & 0xff;
|
||||
b = texel & 0xff;
|
||||
a = texel >> 24;
|
||||
break;
|
||||
case TexFormat::R5G6B5:
|
||||
r = ((texel >> 11) << 3) | (texel >> 13);
|
||||
g = ((texel >> 3) & 0xfc) | ((texel >> 9) & 0x3);
|
||||
b = ((texel & 0x1f) << 3) | ((texel & 0x1c) >> 2);
|
||||
a = 0xff;
|
||||
break;
|
||||
case TexFormat::A1R5G5B5:
|
||||
r = ((texel >> 7) & 0xf8) | ((texel << 1) >> 13);
|
||||
g = ((texel >> 2) & 0xf8) | ((texel >> 7) & 7);
|
||||
b = ((texel & 0x1f) << 3) | ((texel & 0x1c) >> 2);
|
||||
a = 0xff * (texel >> 15);
|
||||
break;
|
||||
case TexFormat::A4R4G4B4:
|
||||
r = ((texel >> 4) & 0xf0) | ((texel >> 8) & 0x0f);
|
||||
g = ((texel & 0xf0) >> 0) | ((texel & 0xf0) >> 4);
|
||||
b = ((texel & 0x0f) << 4) | ((texel & 0x0f) >> 0);
|
||||
a = ((texel >> 8) & 0xf0) | (texel >> 12);
|
||||
break;
|
||||
case TexFormat::A8L8:
|
||||
r = texel & 0xff;
|
||||
g = r;
|
||||
b = r;
|
||||
a = texel >> 8;
|
||||
break;
|
||||
case TexFormat::L8:
|
||||
r = texel & 0xff;
|
||||
g = r;
|
||||
b = r;
|
||||
a = 0xff;
|
||||
break;
|
||||
case TexFormat::A8:
|
||||
r = 0xff;
|
||||
g = 0xff;
|
||||
b = 0xff;
|
||||
a = texel & 0xff;
|
||||
break;
|
||||
default:
|
||||
std::abort();
|
||||
}
|
||||
*lo = (r << 16) + b;
|
||||
*hi = (a << 16) + g;
|
||||
}
|
||||
|
||||
inline void Unpack8888(uint32_t texel, uint32_t* lo, uint32_t* hi) {
|
||||
*lo = texel & 0x00ff00ff;
|
||||
*hi = (texel >> 8) & 0x00ff00ff;
|
||||
}
|
||||
|
||||
inline uint32_t Pack8888(uint32_t lo, uint32_t hi) {
|
||||
return (hi << 8) | lo;
|
||||
}
|
||||
|
||||
inline uint32_t Lerp8888(uint32_t a, uint32_t b, uint32_t f) {
|
||||
return (a + (((b - a) * f) >> 8)) & 0x00ff00ff;
|
||||
}
|
||||
|
||||
template <uint32_t F, typename T = int32_t>
|
||||
void TexAddressLinear(Fixed<F,T> fu,
|
||||
Fixed<F,T> fv,
|
||||
uint32_t log_width,
|
||||
uint32_t log_height,
|
||||
WrapMode wrapu,
|
||||
WrapMode wrapv,
|
||||
uint32_t* addr00,
|
||||
uint32_t* addr01,
|
||||
uint32_t* addr10,
|
||||
uint32_t* addr11,
|
||||
uint32_t* alpha,
|
||||
uint32_t* beta
|
||||
) {
|
||||
auto delta_x = Fixed<F,T>::make(Fixed<F,T>::HALF >> log_width);
|
||||
auto delta_y = Fixed<F,T>::make(Fixed<F,T>::HALF >> log_height);
|
||||
|
||||
uint32_t u0 = Clamp(fu - delta_x, wrapu);
|
||||
uint32_t u1 = Clamp(fu + delta_x, wrapu);
|
||||
uint32_t v0 = Clamp(fv - delta_y, wrapv);
|
||||
uint32_t v1 = Clamp(fv + delta_y, wrapv);
|
||||
|
||||
uint32_t shift_u = (Fixed<F,T>::FRAC - log_width);
|
||||
uint32_t shift_v = (Fixed<F,T>::FRAC - log_height);
|
||||
|
||||
uint32_t x0s = (u0 << 8) >> shift_u;
|
||||
uint32_t y0s = (v0 << 8) >> shift_v;
|
||||
|
||||
uint32_t x0 = x0s >> 8;
|
||||
uint32_t y0 = y0s >> 8;
|
||||
uint32_t x1 = u1 >> shift_u;
|
||||
uint32_t y1 = v1 >> shift_v;
|
||||
|
||||
*addr00 = x0 + (y0 << log_width);
|
||||
*addr01 = x1 + (y0 << log_width);
|
||||
*addr10 = x0 + (y1 << log_width);
|
||||
*addr11 = x1 + (y1 << log_width);
|
||||
|
||||
*alpha = x0s & 0xff;
|
||||
*beta = y0s & 0xff;
|
||||
|
||||
//printf("*** fu=0x%x, fv=0x%x, u0=0x%x, u1=0x%x, v0=0x%x, v1=0x%x, x0=0x%x, x1=0x%x, y0=0x%x, y1=0x%x, addr00=0x%x, addr01=0x%x, addr10=0x%x, addr11=0x%x\n", fu.data(), fv.data(), u0, u1, v0, v1, x0, x1, y0, y1, *addr00, *addr01, *addr10, *addr11);
|
||||
}
|
||||
|
||||
template <uint32_t F, typename T = int32_t>
|
||||
void TexAddressPoint(Fixed<F,T> fu,
|
||||
Fixed<F,T> fv,
|
||||
uint32_t log_width,
|
||||
uint32_t log_height,
|
||||
WrapMode wrapu,
|
||||
WrapMode wrapv,
|
||||
uint32_t* addr
|
||||
) {
|
||||
uint32_t u = Clamp(fu, wrapu);
|
||||
uint32_t v = Clamp(fv, wrapv);
|
||||
|
||||
uint32_t x = u >> (Fixed<F,T>::FRAC - log_width);
|
||||
uint32_t y = v >> (Fixed<F,T>::FRAC - log_height);
|
||||
|
||||
*addr = x + (y << log_width);
|
||||
|
||||
//printf("*** fu=0x%x, fv=0x%x, u=0x%x, v=0x%x, x=0x%x, y=0x%x, addr=0x%x\n", fu.data(), fv.data(), u, v, x, y, *addr);
|
||||
}
|
||||
|
||||
inline uint32_t TexFilterLinear(
|
||||
TexFormat format,
|
||||
uint32_t texel00,
|
||||
uint32_t texel01,
|
||||
uint32_t texel10,
|
||||
uint32_t texel11,
|
||||
uint32_t alpha,
|
||||
uint32_t beta
|
||||
) {
|
||||
uint32_t c01l, c01h;
|
||||
{
|
||||
uint32_t c0l, c0h, c1l, c1h;
|
||||
Unpack8888(format, texel00, &c0l, &c0h);
|
||||
Unpack8888(format, texel01, &c1l, &c1h);
|
||||
c01l = Lerp8888(c0l, c1l, alpha);
|
||||
c01h = Lerp8888(c0h, c1h, alpha);
|
||||
}
|
||||
|
||||
uint32_t c23l, c23h;
|
||||
{
|
||||
uint32_t c2l, c2h, c3l, c3h;
|
||||
Unpack8888(format, texel10, &c2l, &c2h);
|
||||
Unpack8888(format, texel11, &c3l, &c3h);
|
||||
c23l = Lerp8888(c2l, c3l, alpha);
|
||||
c23h = Lerp8888(c2h, c3h, alpha);
|
||||
}
|
||||
|
||||
uint32_t color;
|
||||
{
|
||||
uint32_t cl = Lerp8888(c01l, c23l, beta);
|
||||
uint32_t ch = Lerp8888(c01h, c23h, beta);
|
||||
color = Pack8888(cl, ch);
|
||||
}
|
||||
|
||||
//printf("*** texel00=0x%x, texel01=0x%x, texel10=0x%x, texel11=0x%x, color=0x%x\n", texel00, texel01, texel10, texel11, color);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
inline uint32_t TexFilterPoint(TexFormat format, uint32_t texel) {
|
||||
uint32_t color;
|
||||
{
|
||||
uint32_t cl, ch;
|
||||
Unpack8888(format, texel, &cl, &ch);
|
||||
color = Pack8888(cl, ch);
|
||||
}
|
||||
|
||||
//printf("*** texel=0x%x, color=0x%x\n", texel, color);
|
||||
|
||||
return color;
|
||||
}
|
||||
@@ -1,3 +1,16 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util.h"
|
||||
#include <string.h>
|
||||
|
||||
@@ -7,4 +20,20 @@ const char* fileExtension(const char* filepath) {
|
||||
if (ext == NULL || ext == filepath)
|
||||
return "";
|
||||
return ext + 1;
|
||||
}
|
||||
|
||||
void* aligned_malloc(size_t size, size_t alignment) {
|
||||
// reserve margin for alignment and storing of unaligned address
|
||||
assert((alignment & (alignment - 1)) == 0); // Power of 2 alignment.
|
||||
size_t margin = (alignment-1) + sizeof(void*);
|
||||
void *unaligned_addr = malloc(size + margin);
|
||||
void **aligned_addr = (void**)((uintptr_t)(((uint8_t*)unaligned_addr) + margin) & ~(alignment-1));
|
||||
aligned_addr[-1] = unaligned_addr;
|
||||
return aligned_addr;
|
||||
}
|
||||
|
||||
void aligned_free(void *ptr) {
|
||||
// retreive the stored unaligned address and use it to free the allocation
|
||||
void* unaligned_addr = ((void**)ptr)[-1];
|
||||
free(unaligned_addr);
|
||||
}
|
||||
@@ -1,3 +1,16 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
@@ -49,4 +62,7 @@ const char* fileExtension(const char* filepath);
|
||||
#define DISABLE_WARNING_UNUSED_PARAMETER
|
||||
#define DISABLE_WARNING_UNREFERENCED_FUNCTION
|
||||
#define DISABLE_WARNING_ANONYMOUS_STRUCT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void *aligned_malloc(size_t size, size_t alignment);
|
||||
void aligned_free(void *ptr);
|
||||
55
sim/common/uuid_gen.h
Normal file
55
sim/common/uuid_gen.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright © 2019-2023
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace vortex {
|
||||
|
||||
class UUIDGenerator {
|
||||
public:
|
||||
UUIDGenerator() : ids_(0) {}
|
||||
virtual ~UUIDGenerator() {}
|
||||
|
||||
uint32_t get_uuid(uint64_t PC) {
|
||||
uint32_t id;
|
||||
uint32_t ref;
|
||||
auto it = uuid_map_.find(PC);
|
||||
if (it != uuid_map_.end()) {
|
||||
uint64_t value = it->second;
|
||||
id = value & 0xffff;
|
||||
ref = value >> 16;
|
||||
} else {
|
||||
id = ids_++;
|
||||
ref = -1;
|
||||
}
|
||||
++ref;
|
||||
uint64_t ret = (uint64_t(ref) << 16) | id;
|
||||
uuid_map_[PC] = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
uuid_map_.clear();
|
||||
ids_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::unordered_map<uint64_t, uint32_t> uuid_map_;
|
||||
uint32_t ids_;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user