Vortex 2.0 changes:
+ Microarchitecture optimizations + 64-bit support + Xilinx FPGA support + LLVM-16 support + Refactoring and quality control fixes
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