Merge pull request 'Support Overlays' (#2) from Overlay-The-Beginning_CDDrive into main
Reviewed-on: #2
This commit is contained in:
commit
1bb08c280f
|
@ -1,6 +1,6 @@
|
||||||
#ifndef __JABYENGINE_AUTO_LBA_HPP__
|
#ifndef __JABYENGINE_AUTO_LBA_HPP__
|
||||||
#define __JABYENGINE_AUTO_LBA_HPP__
|
#define __JABYENGINE_AUTO_LBA_HPP__
|
||||||
#include "../../stdint.h"
|
#include "../Auxiliary/bits.hpp"
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
#define __jabyengine_start_lba_request
|
#define __jabyengine_start_lba_request
|
||||||
|
@ -8,8 +8,36 @@ namespace JabyEngine {
|
||||||
#define __jabyengine_end_lba_request EndOfRequest
|
#define __jabyengine_end_lba_request EndOfRequest
|
||||||
|
|
||||||
struct __attribute__((packed)) AutoLBAEntry {
|
struct __attribute__((packed)) AutoLBAEntry {
|
||||||
uint16_t lba;
|
// This layout should make it a bit easier to read the "BitRange" values
|
||||||
uint16_t size_words;
|
static constexpr auto SizeInSectors = BitRange::from_to(22, 31);
|
||||||
|
static constexpr auto IsLZ4Compressed = Bit(19);
|
||||||
|
static constexpr auto LBAValue = BitRange::from_to(0, 18);
|
||||||
|
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
constexpr uint32_t get_lba() const {
|
||||||
|
return bit::value::get_normalized(this->value, AutoLBAEntry::LBAValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uint32_t get_lba() const volatile {
|
||||||
|
return const_cast<const AutoLBAEntry*>(this)->get_lba();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uint32_t get_size_in_sectors() const {
|
||||||
|
return this->value >> SizeInSectors.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr uint32_t get_size_in_sectors() const volatile {
|
||||||
|
return const_cast<const AutoLBAEntry*>(this)->get_size_in_sectors();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_lz4() const {
|
||||||
|
return bit::is_set(this->value, AutoLBAEntry::IsLZ4Compressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_lz4() const volatile {
|
||||||
|
return const_cast<const AutoLBAEntry*>(this)->is_lz4();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,95 @@
|
||||||
#ifndef __JABYENGINE_BITS_HPP__
|
#ifndef __JABYENGINE_BITS_HPP__
|
||||||
#define __JABYENGINE_BITS_HPP__
|
#define __JABYENGINE_BITS_HPP__
|
||||||
#include "../jabyengine_defines.h"
|
#include "../jabyengine_defines.h"
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace bit {
|
namespace bit {
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T set(T raw_value, size_t bit);
|
||||||
|
namespace value {
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T set_normalized(T raw_value, T value, size_t start_bit, size_t length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ClearBit {
|
||||||
|
uint16_t pos;
|
||||||
|
|
||||||
|
constexpr ClearBit(uint16_t bit_pos) : pos(bit_pos) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Bit {
|
||||||
|
uint16_t pos;
|
||||||
|
|
||||||
|
constexpr Bit(uint16_t bit_pos) : pos(bit_pos) {
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ClearBit operator!() const {
|
||||||
|
return ClearBit(this->pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr explicit operator T() const {
|
||||||
|
return bit::set(0, this->pos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BitRange {
|
||||||
|
template<typename T>
|
||||||
|
using RangeValuePair = pair<BitRange, T>;
|
||||||
|
|
||||||
|
uint16_t pos;
|
||||||
|
uint16_t length;
|
||||||
|
|
||||||
|
constexpr BitRange(uint16_t pos, uint16_t length) : pos(pos), length(length) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr BitRange from_to(uint16_t first_bit, uint16_t last_bit) {
|
||||||
|
return BitRange(first_bit, (last_bit - first_bit) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr RangeValuePair<T> with(T value) const {
|
||||||
|
return {*this, value};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr T as_value(T value) const {
|
||||||
|
return bit::value::set_normalized(static_cast<T>(0), value, this->pos, this->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr RangeValuePair<T> range_max() const {
|
||||||
|
return BitRange::with<T>((1 << this->length) - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace bit {
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T clear(T raw_value, size_t bit) {
|
||||||
|
return (raw_value & ~(1 << bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T clear(T raw_value, Bit bit) {
|
||||||
|
return clear(raw_value, bit.pos);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static constexpr T set(T raw_value, size_t bit) {
|
static constexpr T set(T raw_value, size_t bit) {
|
||||||
return (raw_value | (1 << bit));
|
return (raw_value | (1 << bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static constexpr T clear(T raw_value, size_t bit) {
|
static constexpr T set(T raw_value, Bit bit) {
|
||||||
return (raw_value & ~(1 << bit));
|
return set(raw_value, bit.pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T set(T raw_value, ClearBit bit) {
|
||||||
|
return clear(raw_value, bit.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -19,30 +97,52 @@ namespace JabyEngine {
|
||||||
return static_cast<bool>(raw_value & (1 << bit));
|
return static_cast<bool>(raw_value & (1 << bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace value {
|
template<typename T>
|
||||||
template<typename T>
|
static constexpr bool is_set(T raw_value, Bit bit) {
|
||||||
static constexpr T crop_value(T raw_value, size_t length) {
|
return is_set(raw_value, bit.pos);
|
||||||
return (raw_value & ((1 << length) - 1));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
namespace value {
|
||||||
static constexpr T range_mask(size_t start_bit, size_t length) {
|
namespace helper {
|
||||||
return (((1 << length) - 1) << start_bit);
|
template<typename T>
|
||||||
|
static constexpr T crop_value(T raw_value, size_t length) {
|
||||||
|
return (raw_value & ((1 << length) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T range_mask(size_t start_bit, size_t length) {
|
||||||
|
return (((1 << length) - 1) << start_bit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static constexpr T clear_normalized(T raw_value, size_t start_bit, size_t length) {
|
static constexpr T clear_normalized(T raw_value, size_t start_bit, size_t length) {
|
||||||
return (raw_value & ~range_mask<T>(start_bit, length));
|
return (raw_value & ~helper::range_mask<T>(start_bit, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static constexpr T set_normalized(T raw_value, T value, size_t start_bit, size_t length) {
|
static constexpr T set_normalized(T raw_value, T value, size_t start_bit, size_t length) {
|
||||||
return (clear_normalized(raw_value, start_bit, length) | (value << start_bit));
|
return (clear_normalized(raw_value, start_bit, length) | (helper::crop_value(value, length) << start_bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T set_normalized(T raw_value, BitRange bits, T value) {
|
||||||
|
return set_normalized(raw_value, value, bits.pos, bits.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename S>
|
||||||
|
static constexpr T set_normalized(T raw_value, const BitRange::RangeValuePair<S> &value_pair) {
|
||||||
|
return set_normalized(raw_value, value_pair.first, static_cast<T>(value_pair.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static constexpr T get_normalized(T raw_value, size_t start_bit, size_t length) {
|
static constexpr T get_normalized(T raw_value, size_t start_bit, size_t length) {
|
||||||
return (raw_value & range_mask<T>(start_bit, length)) >> start_bit;
|
return helper::crop_value((raw_value & helper::range_mask<T>(start_bit, length)) >> start_bit, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T get_normalized(T raw_value, BitRange range) {
|
||||||
|
return get_normalized(raw_value, range.pos, range.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,66 +3,61 @@
|
||||||
#include "array_range.hpp"
|
#include "array_range.hpp"
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
template<typename T, uint32_t ElementCount>
|
template<typename T>
|
||||||
class FastCircularBuffer {
|
class CircularBuffer {
|
||||||
private:
|
private:
|
||||||
T* start_adr = nullptr;
|
T* start_adr = nullptr;
|
||||||
size_t read_idx = 0;
|
T* end_adr = nullptr;
|
||||||
size_t write_idx = 0;
|
T* read_adr = nullptr;
|
||||||
|
T* write_adr = nullptr;
|
||||||
|
|
||||||
static size_t increment(size_t cur_idx, size_t step) {
|
T* increment(T* cur_element) const {
|
||||||
return ((cur_idx + step) & (ElementCount - 1));
|
cur_element += 1;
|
||||||
|
if(cur_element == this->end_adr) {
|
||||||
|
return this->start_adr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
return cur_element;
|
||||||
FastCircularBuffer() = default;
|
}
|
||||||
|
|
||||||
void setup(T* buffer_start_adr) {
|
|
||||||
this->start_adr = buffer_start_adr;
|
|
||||||
this->read_idx = 0;
|
|
||||||
this->write_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* allocate() {
|
public:
|
||||||
const auto new_idx = FastCircularBuffer::increment(this->write_idx, 1);
|
CircularBuffer() = default;
|
||||||
if(new_idx != this->read_idx) {
|
|
||||||
auto* dst = (this->start_adr + this->write_idx);
|
T* setup(T* buffer_start_adr, size_t elements) {
|
||||||
|
this->start_adr = buffer_start_adr;
|
||||||
this->write_idx = new_idx;
|
this->end_adr = &buffer_start_adr[elements];
|
||||||
return dst;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this->read_adr = this->start_adr;
|
||||||
|
this->write_adr = this->start_adr;
|
||||||
|
return this->end_adr;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* allocate() {
|
||||||
|
T* cur_adr = this->write_adr;
|
||||||
|
T* next_adr = CircularBuffer::increment(cur_adr);
|
||||||
|
if(next_adr == this->read_adr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const T* pop() {
|
else {
|
||||||
if(this->write_idx != this->read_idx) {
|
this->write_adr = next_adr;
|
||||||
const auto* src = (this->start_adr + this->read_idx);
|
return cur_adr;
|
||||||
FastCircularBuffer::drop(1);
|
|
||||||
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void drop(size_t elements) {
|
T* get_next() const {
|
||||||
this->read_idx = FastCircularBuffer::increment(this->read_idx, elements);
|
return this->read_adr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop() {
|
||||||
|
if(CircularBuffer::has_data()) {
|
||||||
|
this->read_adr = CircularBuffer::increment(this->read_adr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr ArrayRange<T> get_first_continious() const {
|
constexpr bool has_data() const {
|
||||||
return {&this->start_adr[this->read_idx], (this->write_idx >= this->read_idx) ? (this->write_idx - this->read_idx) : (ElementCount - this->read_idx)};
|
return (this->read_adr != this->write_adr);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ArrayRange<T> get_second_continious() const {
|
|
||||||
return {this->start_adr, (this->write_idx < this->read_idx) ? this->write_idx : 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool has_data() const {
|
|
||||||
return (this->read_idx != this->write_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static_assert(ElementCount == 2 || ElementCount == 4 || ElementCount == 8 || ElementCount == 16 || ElementCount == 32 || ElementCount == 64 || ElementCount == 128 || ElementCount == 256, "ElementCount for FastCircularBuffer must be power of 2");
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,210 +0,0 @@
|
||||||
#ifndef __JABYENGINE_COMPLEX_BITMAP_HPP__
|
|
||||||
#define __JABYENGINE_COMPLEX_BITMAP_HPP__
|
|
||||||
#include "bits.hpp"
|
|
||||||
|
|
||||||
namespace JabyEngine {
|
|
||||||
struct ClearBitValue {
|
|
||||||
size_t bit;
|
|
||||||
|
|
||||||
constexpr ClearBitValue(size_t bit) : bit(bit) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct Bit {
|
|
||||||
typedef T ValueType;
|
|
||||||
|
|
||||||
size_t value;
|
|
||||||
|
|
||||||
constexpr Bit(size_t value) : value(value) {
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr operator size_t() const {
|
|
||||||
return this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr ClearBitValue operator!() const {
|
|
||||||
return ClearBitValue(this->value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct BitRangeValue {
|
|
||||||
T value;
|
|
||||||
size_t begin;
|
|
||||||
size_t length;
|
|
||||||
|
|
||||||
constexpr BitRangeValue() = default;
|
|
||||||
constexpr BitRangeValue(T value, size_t begin, size_t length) : value(value), begin(begin), length(length) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct BitRange {
|
|
||||||
typedef T ValueType;
|
|
||||||
|
|
||||||
size_t begin;
|
|
||||||
size_t length;
|
|
||||||
|
|
||||||
static constexpr BitRange<T> from_to(size_t start, size_t end) {
|
|
||||||
return {start, (end - start + 1)};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr BitRangeValue<T> with(T value) const {
|
|
||||||
return BitRangeValue(value, this->begin, this->length);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr BitRangeValue<T> max() const {
|
|
||||||
return BitRange<T>::with((1 << this->length) - 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static constexpr __always_inline BitRangeValue<T> operator<<(const BitRange<T>& range, T value) {
|
|
||||||
return BitRangeValue{value, range.begin, range.length};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class ComplexBitMap {
|
|
||||||
public:
|
|
||||||
typedef T UnderlyingType;
|
|
||||||
T raw;
|
|
||||||
|
|
||||||
private:
|
|
||||||
template<typename S>
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& set_va(const S& value) {
|
|
||||||
return this->set(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S, typename...ARGS>
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& set_va(const S& value, const ARGS&...args) {
|
|
||||||
return this->set_va(value).set_va(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
template<typename...ARGS>
|
|
||||||
static constexpr __always_inline ComplexBitMap<T> with(ARGS...args) {
|
|
||||||
return ComplexBitMap().set_va(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Accesssing bits
|
|
||||||
template<typename S>
|
|
||||||
constexpr ComplexBitMap<T>& set_bit(S bit) {
|
|
||||||
this->raw = bit::set(this->raw, static_cast<size_t>(bit));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr void set_bit(S bit) volatile {
|
|
||||||
this->raw = bit::set(this->raw, static_cast<size_t>(bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr ComplexBitMap<T>& clear_bit(S bit) {
|
|
||||||
this->raw = bit::clear(this->raw, static_cast<size_t>(bit));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr void clear_bit(S bit) volatile {
|
|
||||||
this->raw = bit::clear(this->raw, static_cast<size_t>(bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr bool is_bit_set(S bit) {
|
|
||||||
return bit::is_set(this->raw, static_cast<size_t>(bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr bool is_bit_set(S bit) const volatile {
|
|
||||||
return bit::is_set(this->raw, static_cast<size_t>(bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Accessing values
|
|
||||||
template<typename S>
|
|
||||||
constexpr ComplexBitMap<T>& set_value(S value, const BitRange<S>& range) {
|
|
||||||
this->raw = bit::value::set_normalized(this->raw, static_cast<T>(value), range.begin, range.length);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr void set_value(S value, const BitRange<S>& range) volatile {
|
|
||||||
this->raw = bit::value::set_normalized(this->raw, static_cast<T>(value), range.begin, range.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr ComplexBitMap<T>& clear_value(const BitRange<S>& range) {
|
|
||||||
this->raw = bit::value::clear_normalized(this->raw, range.begin, range.length);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr void clear_value(const BitRange<S>& range) volatile {
|
|
||||||
this->raw = bit::value::clear_normalized(this->raw, range.begin, range.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr S get_value(const BitRange<S>& range) const {
|
|
||||||
return static_cast<S>(bit::value::get_normalized(this->raw, range.begin, range.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr S get_value(const BitRange<S>& range) const volatile {
|
|
||||||
return static_cast<S>(bit::value::get_normalized(this->raw, range.begin, range.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
//For easier checking
|
|
||||||
constexpr bool is(Bit<T> bit) const {
|
|
||||||
return ComplexBitMap::is_bit_set(bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool is(Bit<T> bit) const volatile {
|
|
||||||
return ComplexBitMap::is_bit_set(bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For easier constructing
|
|
||||||
template<typename S>
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& set(const BitRange<S>& range, T value) {
|
|
||||||
this->set_value(value, range);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& set(const BitRangeValue<S>& value) {
|
|
||||||
this->set_value(value.value, {value.begin, value.length});
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& set(const Bit<S>& bit) {
|
|
||||||
this->set_bit(bit.value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& set(const ClearBitValue& value) {
|
|
||||||
this->clear_bit(value.bit);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& operator|(const BitRangeValue<T>& value) {
|
|
||||||
this->set_value(value.value, value.range);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& operator|(const Bit<T>& bit) {
|
|
||||||
this->set_bit(bit.value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr __always_inline ComplexBitMap<T>& operator|(const ClearBitValue& value) {
|
|
||||||
this->clear_bit(value.bit);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr __always_inline operator T() const {
|
|
||||||
return this->raw;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //!__JABYENGINE_COMPLEX_BITMAP_HPP__
|
|
|
@ -11,6 +11,10 @@ namespace JabyEngine {
|
||||||
Progress progress;
|
Progress progress;
|
||||||
size_t bytes_ready;
|
size_t bytes_ready;
|
||||||
|
|
||||||
|
constexpr operator bool() const {
|
||||||
|
return this->progress != Progress::Error;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr Result new_error() {
|
static constexpr Result new_error() {
|
||||||
return {Progress::Error, 0};
|
return {Progress::Error, 0};
|
||||||
}
|
}
|
||||||
|
@ -27,6 +31,7 @@ namespace JabyEngine {
|
||||||
private:
|
private:
|
||||||
struct State {
|
struct State {
|
||||||
enum struct Step {
|
enum struct Step {
|
||||||
|
Disabled,
|
||||||
ReadToken,
|
ReadToken,
|
||||||
ObtainLiteralLength,
|
ObtainLiteralLength,
|
||||||
CopyLiterals,
|
CopyLiterals,
|
||||||
|
@ -35,12 +40,23 @@ namespace JabyEngine {
|
||||||
CopyMatch,
|
CopyMatch,
|
||||||
};
|
};
|
||||||
|
|
||||||
Step step = Step::ReadToken;
|
Step step = Step::Disabled;
|
||||||
size_t literal_length = 0;
|
size_t literal_length = 0;
|
||||||
size_t match_length = 0;
|
size_t match_length = 0;
|
||||||
uint16_t match_offset = 0xFFFF;
|
uint16_t match_offset = 0;
|
||||||
|
|
||||||
State() = default;
|
State() = default;
|
||||||
|
|
||||||
|
void enable() {
|
||||||
|
this->step = Step::ReadToken;
|
||||||
|
this->literal_length = 0;
|
||||||
|
this->match_length = 0;
|
||||||
|
this->match_offset = 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disable() {
|
||||||
|
this->step = Step::Disabled;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -56,7 +72,7 @@ namespace JabyEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup(uint8_t* dst_adr);
|
void setup(uint8_t* dst_adr);
|
||||||
void reset();
|
void disable();
|
||||||
|
|
||||||
Result process(ArrayRange<const uint8_t> data, bool is_last);
|
Result process(ArrayRange<const uint8_t> data, bool is_last);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#ifndef __JABYENGINE_CD_FILE_PROCESSOR_HPP__
|
#ifndef __JABYENGINE_CD_FILE_PROCESSOR_HPP__
|
||||||
#define __JABYENGINE_CD_FILE_PROCESSOR_HPP__
|
#define __JABYENGINE_CD_FILE_PROCESSOR_HPP__
|
||||||
#include "../../AutoLBA/auto_lba.hpp"
|
#include "../../AutoLBA/auto_lba.hpp"
|
||||||
|
#include "../../Auxiliary/circular_buffer.hpp"
|
||||||
#include "../../Auxiliary/lz4_decompressor.hpp"
|
#include "../../Auxiliary/lz4_decompressor.hpp"
|
||||||
|
#include "../../System/IOPorts/cd_io.hpp"
|
||||||
#include "../cd_file_types.hpp"
|
#include "../cd_file_types.hpp"
|
||||||
#include "file_processor.hpp"
|
#include "file_processor.hpp"
|
||||||
|
|
||||||
|
@ -10,30 +12,60 @@ extern "C" uint32_t __heap_base;
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
class CDFileProcessor {
|
class CDFileProcessor {
|
||||||
public:
|
public:
|
||||||
|
struct BufferConfiguration {
|
||||||
|
static constexpr size_t SmallSectorCount = 5;
|
||||||
|
static constexpr size_t MediumSectorCount = 16;
|
||||||
|
|
||||||
|
uint32_t* adr = nullptr;
|
||||||
|
size_t sector_count = 0;
|
||||||
|
|
||||||
|
static constexpr BufferConfiguration new_default() {
|
||||||
|
return {&__heap_base, BufferConfiguration::MediumSectorCount};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct JobArray {
|
struct JobArray {
|
||||||
const CDFile* files = nullptr;
|
const CDFile* files = nullptr;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
|
bool next() {
|
||||||
|
this->files += 1;
|
||||||
|
this->size -= 1;
|
||||||
|
|
||||||
|
return this->size > 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileProcessor::State file_pro_state;
|
FileProcessor::State file_state;
|
||||||
LZ4Decompressor lz4_decomp;
|
CircularBuffer<CD_IO::DataSector> circular_buffer;
|
||||||
JobArray jobs;
|
LZ4Decompressor lz4_decomp;
|
||||||
uint8_t* work_area = nullptr;
|
JobArray jobs;
|
||||||
const AutoLBAEntry* lba = nullptr;
|
|
||||||
|
|
||||||
void start_cur_job();
|
void start_cur_job(const AutoLBAEntry* lba, const BufferConfiguration& buf_cfg);
|
||||||
|
bool process_data();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CDFileProcessor() = default;
|
CDFileProcessor() = default;
|
||||||
|
|
||||||
void setup(const volatile AutoLBAEntry* lba, JobArray jobs, uint8_t* work_area = reinterpret_cast<uint8_t*>(&__heap_base));
|
void setup(const volatile AutoLBAEntry* lba, JobArray jobs, const BufferConfiguration& buf_cfg);
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
void setup(const volatile AutoLBAEntry* lba, const CDFile (&file_array)[N], const BufferConfiguration& buf_cfg) {
|
||||||
|
CDFileProcessor::setup(lba, JobArray{file_array, N}, buf_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
Progress process();
|
Progress process();
|
||||||
|
|
||||||
|
bool next(const volatile AutoLBAEntry* lba, const BufferConfiguration& buf_cfg) {
|
||||||
|
if(this->jobs.next()) {
|
||||||
|
CDFileProcessor::start_cur_job(const_cast<const AutoLBAEntry*>(lba), buf_cfg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will be used as the file processor but will work on cd types
|
|
||||||
// Will probably use file_processor
|
|
||||||
// Will also setup the circular buffer for the CD code
|
|
||||||
|
|
||||||
#endif //!__JABYENGINE_CD_FILE_PROCESSOR_HPP__
|
#endif //!__JABYENGINE_CD_FILE_PROCESSOR_HPP__
|
|
@ -20,17 +20,17 @@ namespace JabyEngine {
|
||||||
|
|
||||||
struct Configuration {
|
struct Configuration {
|
||||||
ProcessRoutine process_routine = nullptr;
|
ProcessRoutine process_routine = nullptr;
|
||||||
const uint32_t* data_adr = nullptr;
|
const uint8_t* data_adr = nullptr;
|
||||||
size_t data_word_size = 0ull;
|
size_t data_bytes = 0ull;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static __always_inline Configuration from(GenericProcessRoutine<T> process_routine, const uint32_t* data_adr) {
|
static __always_inline Configuration from(GenericProcessRoutine<T> process_routine, const uint8_t* data_adr) {
|
||||||
return {reinterpret_cast<ProcessRoutine>(process_routine), data_adr};
|
return {reinterpret_cast<ProcessRoutine>(process_routine), data_adr};
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void processed(size_t words) {
|
constexpr void processed(size_t bytes) {
|
||||||
this->data_adr += words;
|
this->data_adr += bytes;
|
||||||
this->data_word_size -= words;
|
this->data_bytes -= bytes;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,18 +39,20 @@ namespace JabyEngine {
|
||||||
Reserved reserved;
|
Reserved reserved;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static __always_inline State from(const T& reserved, const uint32_t* data_adr, GenericProcessRoutine<T> process_routine) {
|
static __always_inline State from(const T& reserved, const uint8_t* data_adr, GenericProcessRoutine<T> process_routine) {
|
||||||
return {Configuration::from(process_routine, data_adr), *reinterpret_cast<const Reserved*>(&reserved)};
|
return {Configuration::from(process_routine, data_adr), *reinterpret_cast<const Reserved*>(&reserved)};
|
||||||
static_assert(sizeof(T) <= sizeof(Reserved));
|
static_assert(sizeof(T) <= sizeof(Reserved));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Progress process(size_t word_size) {
|
Progress process(size_t bytes_ready) {
|
||||||
this->config.data_word_size += word_size;
|
this->config.data_bytes += bytes_ready;
|
||||||
return (*this->config.process_routine)(this->config, this->reserved);
|
return (*this->config.process_routine)(this->config, this->reserved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The nothing state
|
||||||
|
State create(const uint32_t* data_adr, const Nothing& nothing);
|
||||||
State create(const uint32_t* data_adr, const SimpleTIM& file);
|
State create(const uint32_t* data_adr, const SimpleTIM& file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,10 @@ namespace JabyEngine {
|
||||||
|
|
||||||
struct __no_align CDFile {
|
struct __no_align CDFile {
|
||||||
union __no_align Payload {
|
union __no_align Payload {
|
||||||
uint32_t empty;
|
uint32_t raw;
|
||||||
SimpleTIM simple_tim;
|
SimpleTIM simple_tim;
|
||||||
CopyTo copy_to;
|
CopyTo copy_to;
|
||||||
|
Overlay overlay;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t rel_lba_idx;
|
uint8_t rel_lba_idx;
|
||||||
|
@ -31,6 +32,10 @@ namespace JabyEngine {
|
||||||
static constexpr CDFile copy_to(uint8_t rel_lba_idx, uint32_t* dst) {
|
static constexpr CDFile copy_to(uint8_t rel_lba_idx, uint32_t* dst) {
|
||||||
return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::CopyTo, .payload = {.copy_to = CopyTo{dst}}};
|
return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::CopyTo, .payload = {.copy_to = CopyTo{dst}}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr CDFile overlay(uint8_t rel_lba_idx, uint32_t* overlay_dst) {
|
||||||
|
return CDFile{.rel_lba_idx = rel_lba_idx, .type = CDFileType::CopyTo, .payload = {.overlay = Overlay{overlay_dst}}};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif //!__JABYENGINE_CD_FILE_TYPES_HPP__
|
#endif //!__JABYENGINE_CD_FILE_TYPES_HPP__
|
|
@ -1,41 +1,48 @@
|
||||||
#ifndef __JABYENGINE_FILE_TYPES_HPP__
|
#ifndef __JABYENGINE_FILE_TYPES_HPP__
|
||||||
#define __JABYENGINE_FILE_TYPES_HPP__
|
#define __JABYENGINE_FILE_TYPES_HPP__
|
||||||
#include "../Auxiliary/complex_bitmap.hpp"
|
#include "../Auxiliary/bits.hpp"
|
||||||
#include "../jabyengine_defines.h"
|
#include "../jabyengine_defines.h"
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
struct __no_align SimpleTIM : private ComplexBitMap<uint32_t> {
|
struct __no_align Nothing {
|
||||||
static constexpr auto TextureX = BitRange<uint32_t>(0, 8);
|
};
|
||||||
static constexpr auto TextureY = BitRange<uint32_t>(9, 16);
|
|
||||||
static constexpr auto ClutX = BitRange<uint32_t>(17, 22);
|
struct __no_align SimpleTIM {
|
||||||
static constexpr auto ClutY = BitRange<uint32_t>(23, 31);
|
static constexpr auto TextureX = BitRange::from_to(0, 8);
|
||||||
|
static constexpr auto TextureY = BitRange::from_to(9, 16);
|
||||||
|
static constexpr auto ClutX = BitRange::from_to(17, 22);
|
||||||
|
static constexpr auto ClutY = BitRange::from_to(23, 31);
|
||||||
|
|
||||||
|
uint32_t raw;
|
||||||
|
|
||||||
constexpr SimpleTIM() {
|
constexpr SimpleTIM() {
|
||||||
this->raw = 0;
|
this->raw = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr SimpleTIM(uint16_t texX, uint16_t texY, uint16_t clutX, uint16_t clutY) : ComplexBitMap(ComplexBitMap::with(TextureX.with(texX >> 1), TextureY.with(texY >> 1), ClutX.with(clutX >> 4), ClutY.with(clutY))) {
|
constexpr SimpleTIM(uint16_t texX, uint16_t texY, uint16_t clutX, uint16_t clutY) : raw(TextureX.as_value(texX >> 1) | TextureY.as_value(texY >> 1) | ClutX.as_value(clutX >> 4) | ClutY.as_value(clutY)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint16_t getTextureX() const {
|
constexpr uint16_t getTextureX() const {
|
||||||
return (ComplexBitMap<uint32_t>::get_value(SimpleTIM::TextureX) << 1);
|
return bit::value::get_normalized(this->raw, TextureX) << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint16_t getTextureY() const {
|
constexpr uint16_t getTextureY() const {
|
||||||
return (ComplexBitMap<uint32_t>::get_value(SimpleTIM::TextureY) << 1);
|
return bit::value::get_normalized(this->raw, TextureY) << 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint16_t getClutX() const {
|
constexpr uint16_t getClutX() const {
|
||||||
return (ComplexBitMap<uint32_t>::get_value(SimpleTIM::ClutX) << 4);
|
return bit::value::get_normalized(this->raw, SimpleTIM::ClutX) << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint16_t getClutY() const {
|
constexpr uint16_t getClutY() const {
|
||||||
return ComplexBitMap<uint32_t>::get_value(SimpleTIM::ClutY);
|
return bit::value::get_normalized(this->raw, ClutY);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __no_align CopyTo {
|
struct __no_align CopyTo {
|
||||||
uint32_t* dst;
|
uint32_t* dst;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef CopyTo Overlay;
|
||||||
}
|
}
|
||||||
#endif // !__JABYENGINE_FILE_TYPES_HPP__
|
#endif // !__JABYENGINE_FILE_TYPES_HPP__
|
|
@ -22,11 +22,11 @@ namespace JabyEngine {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void enable() {
|
static void enable() {
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::SetDisplayState(GPU_IO::DisplayState::On));
|
GPU_IO::GP1 = GPU_IO::Command::SetDisplayState(GPU_IO::DisplayState::On);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable() {
|
static void disable() {
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::SetDisplayState(GPU_IO::DisplayState::Off));
|
GPU_IO::GP1 = GPU_IO::Command::SetDisplayState(GPU_IO::DisplayState::Off);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#ifndef __JABYENGINE_GPU_TYPES_HPP__
|
#ifndef __JABYENGINE_GPU_TYPES_HPP__
|
||||||
#define __JABYENGINE_GPU_TYPES_HPP__
|
#define __JABYENGINE_GPU_TYPES_HPP__
|
||||||
#include "../jabyengine_defines.h"
|
#include "../jabyengine_defines.h"
|
||||||
#include "../Auxiliary/complex_bitmap.hpp"
|
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace GPU {
|
namespace GPU {
|
||||||
|
@ -41,12 +40,12 @@ namespace JabyEngine {
|
||||||
|
|
||||||
class Color {
|
class Color {
|
||||||
private:
|
private:
|
||||||
static constexpr auto RedRange = BitRange<uint16_t>::from_to(0, 4);
|
static constexpr auto RedRange = BitRange::from_to(0, 4);
|
||||||
static constexpr auto GreenRange = BitRange<uint16_t>::from_to(5, 9);
|
static constexpr auto GreenRange = BitRange::from_to(5, 9);
|
||||||
static constexpr auto BlueRange = BitRange<uint16_t>::from_to(10, 14);
|
static constexpr auto BlueRange = BitRange::from_to(10, 14);
|
||||||
static constexpr auto SemiTransperancyBit = Bit<uint16_t>(15);
|
static constexpr auto SemiTransperancyBit = Bit(15);
|
||||||
|
|
||||||
ComplexBitMap<uint16_t> value = {0};
|
uint16_t value = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr Color from_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
static constexpr Color from_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
@ -58,17 +57,17 @@ namespace JabyEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Color& set_red(uint8_t red) {
|
constexpr Color& set_red(uint8_t red) {
|
||||||
this->value.set_value(static_cast<uint16_t>(red), RedRange);
|
this->value = bit::value::set_normalized(this->value, RedRange.with(red));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Color& set_green(uint8_t green) {
|
constexpr Color& set_green(uint8_t green) {
|
||||||
this->value.set_value(static_cast<uint16_t>(green), GreenRange);
|
this->value = bit::value::set_normalized(this->value, GreenRange.with(green));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Color& set_blue(uint8_t blue) {
|
constexpr Color& set_blue(uint8_t blue) {
|
||||||
this->value.set_value(static_cast<uint16_t>(blue), BlueRange);
|
this->value = bit::value::set_normalized(this->value, BlueRange.with(blue));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,11 +3,9 @@
|
||||||
#include "../AutoLBA/auto_lba.hpp"
|
#include "../AutoLBA/auto_lba.hpp"
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
struct __attribute__((packed)) OverlayHeader {
|
|
||||||
void (*execute)();
|
|
||||||
uint16_t lba_size; //< The size of the OverlayLBA section
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef AutoLBAEntry OverlayLBA;
|
typedef AutoLBAEntry OverlayLBA;
|
||||||
|
|
||||||
|
// Can be used to create dummy values to trick LZ4 into compressing an uncompressed overlay
|
||||||
|
#define __create_dummy_fill(length) static const uint8_t __section(".keep.dummy") __used DummyFilling[length] = {0x0}
|
||||||
}
|
}
|
||||||
#endif //!__JABYENGINE_OVERLAY__HPP__
|
#endif //!__JABYENGINE_OVERLAY__HPP__
|
|
@ -4,10 +4,7 @@
|
||||||
// No include here because this header should be included in a namespace and we don't want multiple namespace definitions of OverlayHeader and OverlayLBA
|
// No include here because this header should be included in a namespace and we don't want multiple namespace definitions of OverlayHeader and OverlayLBA
|
||||||
|
|
||||||
#include "../AutoLBA/auto_lba_declaration.hpp"
|
#include "../AutoLBA/auto_lba_declaration.hpp"
|
||||||
extern const JabyEngine::OverlayHeader overlay_header;
|
|
||||||
|
|
||||||
#define __declare_overlay_header(function, enum_struct) \
|
#define __declare_overlay_header(function, enum_struct) \
|
||||||
__declare_lba_header(enum_struct); \
|
__declare_lba_header(enum_struct)
|
||||||
[[gnu::used]] \
|
|
||||||
const JabyEngine::OverlayHeader __section(".header") overlay_header = {.execute = &function, .lba_size = static_cast<uint16_t>(enum_struct::EndOfRequest)};
|
|
||||||
#endif //!__JABYENGINE_OVERLAY_DECLARATION__HPP__
|
#endif //!__JABYENGINE_OVERLAY_DECLARATION__HPP__
|
|
@ -4,6 +4,18 @@
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace CD_IO {
|
namespace CD_IO {
|
||||||
|
struct DataSector {
|
||||||
|
static constexpr size_t SizeBytes = 2048;
|
||||||
|
static constexpr size_t SizeWords = (SizeBytes/sizeof(uint32_t));
|
||||||
|
|
||||||
|
uint32_t data[SizeWords];
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr T words_to_sectors(T size) {
|
||||||
|
return (size + static_cast<T>(DataSector::SizeWords - 1))/static_cast<T>(DataSector::SizeWords);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum Index {
|
enum Index {
|
||||||
Index0 = 0,
|
Index0 = 0,
|
||||||
Index1 = 1,
|
Index1 = 1,
|
||||||
|
@ -19,56 +31,74 @@ namespace JabyEngine {
|
||||||
static constexpr uint8_t Max = 0xFF;
|
static constexpr uint8_t Max = 0xFF;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct IndexStatus : public ComplexBitMap<uint8_t> {
|
__declare_io_type(Mode, uint8_t,
|
||||||
static constexpr auto PortIndex = BitRange<Index>::from_to(0, 1);
|
static constexpr auto DoubleSpeed = Bit(7);
|
||||||
static constexpr auto HasXAFifoData = Bit<uint8_t>(2);
|
static constexpr auto SingleSpeed = !DoubleSpeed;
|
||||||
static constexpr auto IsParameterFifoEmpty = Bit<uint8_t>(3);
|
static constexpr auto XADPCM = Bit(6);
|
||||||
static constexpr auto HasParameterFifoSpace = Bit<uint8_t>(4);
|
static constexpr auto WholeSector = Bit(5);
|
||||||
static constexpr auto HasResponseFifoData = Bit<uint8_t>(5);
|
static constexpr auto DataSector = !WholeSector;
|
||||||
static constexpr auto HasDataFifoData = Bit<uint8_t>(6);
|
static constexpr auto UseXAFilter = Bit(3);
|
||||||
static constexpr auto IsTransmissionBusy = Bit<uint8_t>(7);
|
static constexpr auto AudioPlayIRQ = Bit(2);
|
||||||
} IndexStatus_t;
|
static constexpr auto AutoPauseTrack = Bit(1);
|
||||||
|
static constexpr auto CDDA = Bit(0);
|
||||||
|
);
|
||||||
|
|
||||||
struct InterruptEnable : public ComplexBitMap<uint8_t> {
|
__declare_io_type(IndexStatus, uint8_t,
|
||||||
static constexpr auto InterruptTypValue = BitRange<uint8_t>::from_to(0, 2);
|
static constexpr auto PortIndex = BitRange::from_to(0, 1);
|
||||||
static constexpr auto InterruptExtended = BitRange<uint8_t>::from_to(0, 4);
|
static constexpr auto HasXAFifoData = Bit(2);
|
||||||
static constexpr auto UnknownIRQ = Bit<uint8_t>(3);
|
static constexpr auto IsParameterFifoEmpty = Bit(3);
|
||||||
static constexpr auto CommandStartIRQ = Bit<uint8_t>(4);
|
static constexpr auto HasParameterFifoSpace = Bit(4);
|
||||||
};
|
static constexpr auto HasResponseFifoData = Bit(5);
|
||||||
typedef InterruptEnable InterruptFlag;
|
static constexpr auto HasDataFifoData = Bit(6);
|
||||||
|
static constexpr auto IsTransmissionBusy = Bit(7);
|
||||||
|
);
|
||||||
|
|
||||||
struct Request : public ComplexBitMap<uint8_t> {
|
__declare_io_type(InterruptEnable, uint8_t,
|
||||||
static constexpr auto WantCommandStartIRQ = Bit<uint8_t>(5);
|
static constexpr auto InterruptTypValue = BitRange::from_to(0, 2);
|
||||||
static constexpr auto WantData = Bit<uint8_t>(7);
|
static constexpr auto InterruptExtended = BitRange::from_to(0, 4);
|
||||||
};
|
static constexpr auto UnknownIRQ = Bit(3);
|
||||||
|
static constexpr auto CommandStartIRQ = Bit(4);
|
||||||
|
);
|
||||||
|
typedef InterruptEnable_v InterruptFlag_v;
|
||||||
|
|
||||||
struct SoundMapCoding : public ComplexBitMap<uint8_t> {
|
__declare_io_type(Request, uint8_t,
|
||||||
static constexpr auto Stereo = Bit<uint8_t>(0);
|
static constexpr auto WantCommandStartIRQ = Bit(5);
|
||||||
|
static constexpr auto WantData = Bit(7);
|
||||||
|
|
||||||
|
void want_data() {
|
||||||
|
this->raw_value = static_cast<uint8_t>(Self::WantData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
this->raw_value = 0;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
__declare_io_type(SoundMapCoding, uint8_t,
|
||||||
|
static constexpr auto Stereo = Bit(0);
|
||||||
static constexpr auto Mono = !Stereo;
|
static constexpr auto Mono = !Stereo;
|
||||||
static constexpr auto SampleRate_18900hz = Bit<uint8_t>(2);
|
static constexpr auto SampleRate_18900hz = Bit(2);
|
||||||
static constexpr auto SampleRate_37800hz = !SampleRate_18900hz;
|
static constexpr auto SampleRate_37800hz = !SampleRate_18900hz;
|
||||||
static constexpr auto BitsPerSample8 = Bit<uint8_t>(4);
|
static constexpr auto BitsPerSample8 = Bit(4);
|
||||||
static constexpr auto BitsPerSample4 = !BitsPerSample8;
|
static constexpr auto BitsPerSample4 = !BitsPerSample8;
|
||||||
static constexpr auto Emphasis = Bit<uint8_t>(6);
|
static constexpr auto Emphasis = Bit(6);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct AudioVolumeApply : public ComplexBitMap<uint8_t> {
|
__declare_io_type(AudioVolumeApply, uint8_t,
|
||||||
static constexpr auto Mute = Bit<uint8_t>(0);
|
static constexpr auto Mute = Bit(0);
|
||||||
static constexpr auto ApplyChanges = Bit<uint8_t>(5);
|
static constexpr auto ApplyChanges = Bit(5);
|
||||||
};
|
);
|
||||||
|
|
||||||
typedef VolatilePOD<uint8_t> ResponseFifo_t;
|
__declare_io_type(ResponseFifo, uint8_t,);
|
||||||
typedef VolatilePOD<uint8_t> CommandFifo_t;
|
__declare_io_type(CommandFifo, uint8_t,);
|
||||||
typedef VolatilePOD<uint8_t> DataFifo_t;
|
__declare_io_type(DataFifo, uint8_t,);
|
||||||
typedef VolatilePOD<uint16_t> DataFifo16_t;
|
__declare_io_type(DataFifo16, uint16_t,);
|
||||||
typedef VolatilePOD<uint8_t> ParameterFifo_t;
|
__declare_io_type(ParameterFifo, uint8_t,);
|
||||||
typedef VolatilePOD<uint8_t> SoundMapDataOut_t;
|
__declare_io_type(SoundMapDataOut, uint8_t,);
|
||||||
typedef VolatilePOD<CDDAVolume::Type> VolumeRegister_t;
|
__declare_io_type(LeftCD2LeftSPU, CDDAVolume::Type,);
|
||||||
typedef VolatileBitMapPOD<InterruptEnable> InterruptEnableRegister_t;
|
__declare_io_type(LeftCD2RightSPU, CDDAVolume::Type,);
|
||||||
typedef VolatileBitMapPOD<InterruptFlag> InterruptFlagRegister_t;
|
__declare_io_type(RightCD2RightSPU,CDDAVolume::Type,);
|
||||||
typedef VolatileBitMapPOD<Request> RequestRegister_t;
|
__declare_io_type(RightCD2LeftSPU, CDDAVolume::Type,);
|
||||||
typedef VolatileBitMapPOD<SoundMapCoding> SoundMapCodingInfo_t;
|
|
||||||
typedef VolatileBitMapPOD<AudioVolumeApply> AudioVolumeApplyChange_t;
|
|
||||||
|
|
||||||
struct Interrupt {
|
struct Interrupt {
|
||||||
enum Type : uint8_t {
|
enum Type : uint8_t {
|
||||||
|
@ -80,110 +110,110 @@ namespace JabyEngine {
|
||||||
DiskError = 5
|
DiskError = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
static void enable(InterruptEnableRegister_t& port) {
|
static void enable(InterruptEnable_v& port) {
|
||||||
port.write(InterruptEnable::InterruptTypValue.max());
|
port.set(InterruptEnable_t::InterruptTypValue.range_max<uint8_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_extended(InterruptEnableRegister_t& port) {
|
static void enable_extended(InterruptEnable_v& port) {
|
||||||
port.write({InterruptEnable::with(InterruptEnable::InterruptTypValue.max(), InterruptEnable::UnknownIRQ, InterruptEnable::CommandStartIRQ)});
|
port = InterruptEnable_t::from(InterruptEnable_t::InterruptTypValue.range_max<uint8_t>(), InterruptEnable_t::UnknownIRQ, InterruptEnable_t::CommandStartIRQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type get_type(const InterruptFlagRegister_t& port) {
|
static Type get_type(const InterruptFlag_v& port) {
|
||||||
return static_cast<Type>(port.read().get_value(InterruptFlag::InterruptTypValue));
|
return static_cast<Type>(port.get(InterruptFlag_v::InterruptTypValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ack(InterruptFlagRegister_t& port) {
|
static void ack(InterruptFlag_v& port) {
|
||||||
port.write(InterruptFlag::InterruptTypValue.max());
|
port.set(InterruptFlag_v::InterruptTypValue.range_max<uint8_t>());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ack_extended(InterruptFlagRegister_t& port) {
|
static void ack_extended(InterruptFlag_v& port) {
|
||||||
port.write({InterruptFlag::with(InterruptFlag::InterruptTypValue.max(), InterruptEnable::UnknownIRQ, InterruptEnable::CommandStartIRQ)});
|
port = InterruptFlag_v::from(InterruptFlag_v::InterruptTypValue.range_max<uint8_t>(), InterruptEnable_v::UnknownIRQ, InterruptEnable_v::CommandStartIRQ);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Command {
|
struct Command {
|
||||||
struct Info {
|
struct Desc {
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
Interrupt::Type complete_irq;
|
Interrupt::Type complete_irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Info GetStat{0x01, Interrupt::Type::Acknowledge};
|
static constexpr Desc GetStat{0x01, Interrupt::Type::Acknowledge};
|
||||||
static constexpr Info SetLoc{0x02, Interrupt::Type::Acknowledge};
|
static constexpr Desc SetLoc{0x02, Interrupt::Type::Acknowledge};
|
||||||
static constexpr Info ReadN{0x06, Interrupt::Type::DataReady};
|
static constexpr Desc ReadN{0x06, Interrupt::Type::DataReady};
|
||||||
static constexpr Info Pause{0x09, Interrupt::Type::Complete};
|
static constexpr Desc Pause{0x09, Interrupt::Type::Complete};
|
||||||
static constexpr Info Init{0x0A, Interrupt::Type::Complete};
|
static constexpr Desc Init{0x0A, Interrupt::Type::Complete};
|
||||||
static constexpr Info SetMode{0x0E, Interrupt::Type::Acknowledge};
|
static constexpr Desc SetMode{0x0E, Interrupt::Type::Acknowledge};
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr auto IORegister1Adr = 0x1F801801;
|
static constexpr auto IORegister1Adr = 0x1F801801;
|
||||||
static constexpr auto IORegister2Adr = 0x1F801802;
|
static constexpr auto IORegister2Adr = 0x1F801802;
|
||||||
static constexpr auto IORegister3Adr = 0x1F801803;
|
static constexpr auto IORegister3Adr = 0x1F801803;
|
||||||
|
|
||||||
__declare_io_port_global(IndexStatus_t, IndexStatus, 0x1F801800);
|
__declare_new_io_port(IndexStatus, 0x1F801800);
|
||||||
|
|
||||||
#define __declare_index_io_port(type, name, adr) __cast_io_adr_with_type(inline, type, name, adr)
|
#define __declare_index_io_port(type, name, adr) __cast_io_adr_with_type(inline, type, name, adr)
|
||||||
#define __declare_index_io_port_const(type, name, adr) __cast_io_adr_with_type(const inline, type, name, adr)
|
#define __declare_index_io_port_const(type, name, adr) __cast_io_adr_with_type(const inline, type, name, adr)
|
||||||
|
|
||||||
struct PortIndex0 {
|
struct PortIndex0 {
|
||||||
__declare_index_io_port_const(ResponseFifo_t, ResponseFifo, IORegister1Adr);
|
__declare_new_const_io_port(ResponseFifo, IORegister1Adr);
|
||||||
__declare_index_io_port( CommandFifo_t, CommandFifo, IORegister1Adr);
|
__declare_new_io_port(CommandFifo, IORegister1Adr);
|
||||||
|
|
||||||
__declare_index_io_port_const(DataFifo_t, DataFifo, IORegister2Adr);
|
__declare_new_const_io_port(DataFifo, IORegister2Adr);
|
||||||
__declare_index_io_port_const(DataFifo16_t, DataFifo16, IORegister2Adr);
|
__declare_new_const_io_port(DataFifo16, IORegister2Adr);
|
||||||
__declare_index_io_port( ParameterFifo_t, ParameterFifo, IORegister2Adr);
|
__declare_new_io_port(ParameterFifo, IORegister2Adr);
|
||||||
|
|
||||||
__declare_index_io_port_const(InterruptEnableRegister_t, InterruptEnableRegister, IORegister3Adr);
|
__declare_new_const_io_port(InterruptEnable, IORegister3Adr);
|
||||||
__declare_index_io_port( RequestRegister_t, RequestRegister, IORegister3Adr);
|
__declare_new_io_port(Request, IORegister3Adr);
|
||||||
|
|
||||||
static void change_to() {
|
static void change_to() {
|
||||||
IndexStatus.write({static_cast<uint8_t>(Index::Index0)});
|
IndexStatus = Index::Index0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PortIndex1 {
|
struct PortIndex1 {
|
||||||
__declare_index_io_port_const(ResponseFifo_t, ResponseFifo, IORegister1Adr);
|
__declare_new_const_io_port(ResponseFifo, IORegister1Adr);
|
||||||
__declare_index_io_port( SoundMapDataOut_t, SoundMapDataOut, IORegister1Adr);
|
__declare_new_io_port(SoundMapDataOut, IORegister1Adr);
|
||||||
|
|
||||||
__declare_index_io_port_const(DataFifo_t, DataFifo, IORegister2Adr);
|
__declare_new_const_io_port(DataFifo, IORegister2Adr);
|
||||||
__declare_index_io_port_const(DataFifo16_t, DataFifo16, IORegister2Adr);
|
__declare_new_const_io_port(DataFifo16, IORegister2Adr);
|
||||||
__declare_index_io_port( InterruptEnableRegister_t, InterruptEnableRegister, IORegister2Adr);
|
__declare_new_io_port(InterruptEnable, IORegister2Adr);
|
||||||
|
|
||||||
__declare_index_io_port(InterruptFlagRegister_t, InterruptFlagRegister, IORegister3Adr);
|
__declare_new_io_port(InterruptFlag, IORegister3Adr);
|
||||||
|
|
||||||
static void change_to() {
|
static void change_to() {
|
||||||
IndexStatus.write({static_cast<uint8_t>(Index::Index1)});
|
IndexStatus = Index::Index1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PortIndex2 {
|
struct PortIndex2 {
|
||||||
__declare_index_io_port_const(ResponseFifo_t, ResponseFifo, IORegister1Adr);
|
__declare_new_const_io_port(ResponseFifo, IORegister1Adr);
|
||||||
__declare_index_io_port( SoundMapCodingInfo_t, SoundMapCodingInfo, IORegister1Adr);
|
__declare_new_io_port(SoundMapCoding, IORegister1Adr);
|
||||||
|
|
||||||
__declare_index_io_port_const(DataFifo_t, DataFifo, IORegister2Adr);
|
__declare_new_const_io_port(DataFifo, IORegister2Adr);
|
||||||
__declare_index_io_port_const(DataFifo16_t, DataFifo16, IORegister2Adr);
|
__declare_new_const_io_port(DataFifo16, IORegister2Adr);
|
||||||
__declare_index_io_port( VolumeRegister_t, LeftCD2LeftSPU, IORegister2Adr);
|
__declare_new_io_port(LeftCD2LeftSPU, IORegister2Adr);
|
||||||
|
|
||||||
__declare_index_io_port_const(InterruptEnableRegister_t, InterruptEnableRegister, IORegister3Adr);
|
__declare_new_const_io_port(InterruptEnable, IORegister3Adr);
|
||||||
__declare_index_io_port( VolumeRegister_t, LeftCD2RightSPU, IORegister3Adr);
|
__declare_new_io_port(LeftCD2RightSPU, IORegister3Adr);
|
||||||
|
|
||||||
static void change_to() {
|
static void change_to() {
|
||||||
IndexStatus.write({static_cast<uint8_t>(Index::Index2)});
|
IndexStatus = Index::Index2;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PortIndex3 {
|
struct PortIndex3 {
|
||||||
__declare_index_io_port_const(ResponseFifo_t, ResponseFifo, IORegister1Adr);
|
__declare_new_const_io_port(ResponseFifo, IORegister1Adr);
|
||||||
__declare_index_io_port( VolumeRegister_t, RightCD2RightSPU, IORegister1Adr);
|
__declare_new_io_port(RightCD2RightSPU, IORegister1Adr);
|
||||||
|
|
||||||
__declare_index_io_port_const(DataFifo_t, DataFifo, IORegister2Adr);
|
__declare_new_const_io_port(DataFifo, IORegister2Adr);
|
||||||
__declare_index_io_port_const(DataFifo16_t, DataFifo16, IORegister2Adr);
|
__declare_new_const_io_port(DataFifo16, IORegister2Adr);
|
||||||
__declare_index_io_port( VolumeRegister_t, RightCD2LeftSPU, IORegister1Adr);
|
__declare_new_io_port(RightCD2LeftSPU, IORegister1Adr);
|
||||||
|
|
||||||
__declare_index_io_port_const(InterruptFlagRegister_t, InterruptFlagRegister, IORegister3Adr);
|
__declare_new_const_io_port(InterruptFlag, IORegister3Adr);
|
||||||
__declare_index_io_port( AudioVolumeApplyChange_t, AudioVolumeApplyChange, IORegister3Adr);
|
__declare_new_io_port(AudioVolumeApply, IORegister3Adr);
|
||||||
|
|
||||||
static void change_to() {
|
static void change_to() {
|
||||||
IndexStatus.write({static_cast<uint8_t>(Index::Index3)});
|
IndexStatus = Index::Index3;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,130 +4,152 @@
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace DMA_IO {
|
namespace DMA_IO {
|
||||||
struct MADR : public ComplexBitMap<uint32_t> {
|
__declare_io_type(MADR, uint32_t,
|
||||||
static constexpr auto MemoryAdr = BitRange<uint32_t>::from_to(0, 23);
|
static constexpr auto MemoryAdr = BitRange::from_to(0, 23);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct BCR : public ComplexBitMap<uint32_t> {
|
__declare_io_type(BCR, uint32_t,
|
||||||
struct __no_align SyncMode0 {
|
struct SyncMode0 {
|
||||||
static constexpr auto NumberOfWords = BitRange<uint16_t>::from_to(0, 15);
|
static constexpr auto NumberOfWords = BitRange::from_to(0, 15);
|
||||||
static constexpr auto CD_OneBlock = Bit<uint16_t>(16);
|
static constexpr auto CD_OneBlock = Bit(16);
|
||||||
|
|
||||||
|
static constexpr Self for_cd() {
|
||||||
|
// v Should be replaced with a named constant
|
||||||
|
return Self::from(SyncMode0::CD_OneBlock, SyncMode0::NumberOfWords.with(512));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SyncMode1 : public ComplexBitMap<uint32_t> {
|
struct SyncMode1 {
|
||||||
static constexpr auto BlockSize = BitRange<uint32_t>::from_to(0, 15);
|
static constexpr auto BlockSize = BitRange::from_to(0, 15);
|
||||||
static constexpr auto BlockAmount = BitRange<uint32_t>::from_to(16, 31);
|
static constexpr auto BlockAmount = BitRange::from_to(16, 31);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SyncMode2 {
|
struct SyncMode2 {
|
||||||
};
|
};
|
||||||
};
|
);
|
||||||
|
|
||||||
struct CHCHR : public ComplexBitMap<uint32_t> {
|
__declare_io_type(CHCHR, uint32_t,
|
||||||
enum _SyncMode {
|
enum SyncMode_t {
|
||||||
Sync0 = 0, //Start immediately,
|
Sync0 = 0, //Start immediately,
|
||||||
Sync1 = 1, //Sync blocks to DMA requests
|
Sync1 = 1, //Sync blocks to DMA requests
|
||||||
Sync2 = 2, //Linked List
|
Sync2 = 2, //Linked List
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr auto ManualStart = Bit<uint32_t>(28);
|
static constexpr auto ManualStart = Bit(28);
|
||||||
|
|
||||||
static constexpr auto Start = Bit<uint32_t>(24);
|
static constexpr auto Start = Bit(24);
|
||||||
static constexpr auto Busy = Start;
|
static constexpr auto Busy = Start;
|
||||||
|
|
||||||
static constexpr auto ChoppingCPUWindowSize = BitRange<uint32_t>::from_to(20, 22);
|
static constexpr auto ChoppingCPUWindowSize = BitRange::from_to(20, 22);
|
||||||
static constexpr auto ChoppingDMAWindowSize = BitRange<uint32_t>::from_to(16, 18);
|
static constexpr auto ChoppingDMAWindowSize = BitRange::from_to(16, 18);
|
||||||
|
|
||||||
static constexpr auto SyncMode = BitRange<_SyncMode>::from_to(9, 10);
|
static constexpr auto SyncMode = BitRange::from_to(9, 10);
|
||||||
static constexpr auto UseSyncMode0 = SyncMode.with(Sync0);
|
static constexpr auto UseSyncMode0 = SyncMode.with(Sync0);
|
||||||
static constexpr auto UseSyncMode1 = SyncMode.with(Sync1);
|
static constexpr auto UseSyncMode1 = SyncMode.with(Sync1);
|
||||||
static constexpr auto UseSyncMode2 = SyncMode.with(Sync2);
|
static constexpr auto UseSyncMode2 = SyncMode.with(Sync2);
|
||||||
|
|
||||||
static constexpr auto UseChopping = Bit<uint32_t>(8);
|
static constexpr auto UseChopping = Bit(8);
|
||||||
|
|
||||||
static constexpr auto MemoryAdrDecreaseBy4 = Bit<uint32_t>(1);
|
static constexpr auto MemoryAdrDecreaseBy4 = Bit(1);
|
||||||
static constexpr auto MemoryAdrIncreaseBy4 = !MemoryAdrDecreaseBy4;
|
static constexpr auto MemoryAdrIncreaseBy4 = !MemoryAdrDecreaseBy4;
|
||||||
|
|
||||||
static constexpr auto FromMainRAM = Bit<uint32_t>(0);
|
static constexpr auto FromMainRAM = Bit(0);
|
||||||
static constexpr auto ToMainRAM = !FromMainRAM;
|
static constexpr auto ToMainRAM = !FromMainRAM;
|
||||||
|
|
||||||
static constexpr CHCHR StartMDECin() {
|
static constexpr Self StartMDECin() {
|
||||||
return CHCHR{0x01000201};
|
return Self{0x01000201};
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr CHCHR StartMDECout() {
|
static constexpr Self StartMDECout() {
|
||||||
return CHCHR{0x01000200};
|
return Self{0x01000200};
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr CHCHR StartGPUReceive() {
|
static constexpr Self StartGPUReceive() {
|
||||||
return CHCHR{0x01000201};
|
return Self{0x01000201};
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr CHCHR StartCDROM() {
|
static constexpr Self StartCDROM() {
|
||||||
return CHCHR{0x11000000};
|
return Self{0x11000000};
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr CHCHR StartSPUReceive() {
|
static constexpr Self StartSPUReceive() {
|
||||||
return CHCHR{0x01000201};
|
return Self{0x01000201};
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr CHCHR StartOTC() {
|
static constexpr Self StartOTC() {
|
||||||
return CHCHR{0x11000002};
|
return Self{0x11000002};
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
|
|
||||||
struct __no_align Registers {
|
struct __no_align Registers {
|
||||||
VolatileBitMapPOD<MADR> adr;
|
MADR_v adr;
|
||||||
VolatileBitMapPOD<BCR> block_ctrl;
|
BCR_v block_ctrl;
|
||||||
VolatileBitMapPOD<CHCHR> channel_ctrl;
|
CHCHR_v channel_ctrl;
|
||||||
|
|
||||||
|
void set_adr(uintptr_t adr) {
|
||||||
|
this->adr.set(MADR_t::MemoryAdr.with(adr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait() {
|
||||||
|
while(this->channel_ctrl.is_set(CHCHR_t::Busy));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Those types do not need to be volatile because there members are
|
||||||
|
typedef Registers MDECin_v;
|
||||||
|
typedef Registers MDECout_v;
|
||||||
|
typedef Registers GPU_v;
|
||||||
|
typedef Registers CDROM_v;
|
||||||
|
typedef Registers SPU_v;
|
||||||
|
typedef Registers PIO_v;
|
||||||
|
typedef Registers OTC_v;
|
||||||
|
|
||||||
//0: Highest, 7: Lowest
|
//0: Highest, 7: Lowest
|
||||||
typedef uint32_t Priority;
|
typedef uint32_t Priority;
|
||||||
static constexpr Priority HighestPriority = 0;
|
static constexpr Priority HighestPriority = 0;
|
||||||
static constexpr Priority LowestPriority = 7;
|
static constexpr Priority LowestPriority = 7;
|
||||||
|
|
||||||
struct DMAControlRegister : public ComplexBitMap<uint32_t> {
|
__declare_io_type(DPCR, uint32_t,
|
||||||
static constexpr auto OTCEnable = Bit<uint32_t>(27);
|
static constexpr auto OTCEnable = Bit(27);
|
||||||
static constexpr auto OTCPriority = BitRange<Priority>::from_to(24, 26);
|
static constexpr auto OTCPriority = BitRange::from_to(24, 26);
|
||||||
|
|
||||||
static constexpr auto PIOEnable = Bit<uint32_t>(23);
|
static constexpr auto PIOEnable = Bit(23);
|
||||||
static constexpr auto PIOPriority = BitRange<Priority>::from_to(20, 22);
|
static constexpr auto PIOPriority = BitRange::from_to(20, 22);
|
||||||
|
|
||||||
static constexpr auto SPUEnable = Bit<uint32_t>(19);
|
static constexpr auto SPUEnable = Bit(19);
|
||||||
static constexpr auto SPUPriority = BitRange<Priority>::from_to(16, 18);
|
static constexpr auto SPUPriority = BitRange::from_to(16, 18);
|
||||||
|
|
||||||
static constexpr auto CDROMEnable = Bit<uint32_t>(15);
|
static constexpr auto CDROMEnable = Bit(15);
|
||||||
static constexpr auto CDROMPriority = BitRange<Priority>::from_to(12, 14);
|
static constexpr auto CDROMPriority = BitRange::from_to(12, 14);
|
||||||
|
|
||||||
static constexpr auto GPUEnable = Bit<uint32_t>(11);
|
static constexpr auto GPUEnable = Bit(11);
|
||||||
static constexpr auto GPUPriority = BitRange<Priority>::from_to(8, 10);
|
static constexpr auto GPUPriority = BitRange::from_to(8, 10);
|
||||||
|
|
||||||
static constexpr auto MDECoutEnable = Bit<uint32_t>(7);
|
static constexpr auto MDECoutEnable = Bit(7);
|
||||||
static constexpr auto MDECoutPriority = BitRange<Priority>::from_to(4, 6);
|
static constexpr auto MDECoutPriority = BitRange::from_to(4, 6);
|
||||||
|
|
||||||
static constexpr auto MDECinEnable = Bit<uint32_t>(3);
|
static constexpr auto MDECinEnable = Bit(3);
|
||||||
static constexpr auto MDECinPriority = BitRange<Priority>::from_to(0, 2);
|
static constexpr auto MDECinPriority = BitRange::from_to(0, 2);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct DMAInterruptRegister : public ComplexBitMap<uint32_t> {
|
__declare_io_type(DICR, uint32_t,
|
||||||
static constexpr auto MasterEnable = Bit<uint32_t>(31);
|
static constexpr auto MasterEnable = Bit(31);
|
||||||
static constexpr auto Flags = BitRange<uint32_t>::from_to(24, 30);
|
static constexpr auto Flags = BitRange::from_to(24, 30);
|
||||||
static constexpr auto MasterEnableDPCR = Bit<uint32_t>(23);
|
static constexpr auto MasterEnableDPCR = Bit(23);
|
||||||
static constexpr auto EnableDPCR = BitRange<uint32_t>::from_to(16, 22);
|
static constexpr auto EnableDPCR = BitRange::from_to(16, 22);
|
||||||
static constexpr auto ForceIRQ = Bit<uint32_t>(15);
|
static constexpr auto ForceIRQ = Bit(15);
|
||||||
};
|
);
|
||||||
|
|
||||||
__declare_io_port_global_struct(Registers, MDECin, 0x1F801080);
|
__declare_new_io_port(MDECin, 0x1F801080);
|
||||||
__declare_io_port_global_struct(Registers, MDECout, 0x1F801090);
|
__declare_new_io_port(MDECout, 0x1F801090);
|
||||||
__declare_io_port_global_struct(Registers, GPU, 0x1F8010A0);
|
__declare_new_io_port(GPU, 0x1F8010A0);
|
||||||
__declare_io_port_global_struct(Registers, CDROM, 0x1F8010B0);
|
__declare_new_io_port(CDROM, 0x1F8010B0);
|
||||||
__declare_io_port_global_struct(Registers, SPU, 0x1F8010C0);
|
__declare_new_io_port(SPU, 0x1F8010C0);
|
||||||
__declare_io_port_global_struct(Registers, PIO, 0x1F8010D0);
|
__declare_new_io_port(PIO, 0x1F8010D0);
|
||||||
__declare_io_port_global_struct(Registers, OTC, 0x1F8010E0);
|
__declare_new_io_port(OTC, 0x1F8010E0);
|
||||||
|
|
||||||
__declare_io_port_global(DMAControlRegister, DPCR, 0x1F8010F0);
|
__declare_new_io_port(DPCR, 0x1F8010F0);
|
||||||
__declare_io_port_global(DMAInterruptRegister, DICR, 0x1F8010F4);
|
__declare_new_io_port(DICR, 0x1F8010F4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //!__JABYENGINE_DMA_IO_HPP__
|
#endif //!__JABYENGINE_DMA_IO_HPP__
|
|
@ -47,124 +47,162 @@ namespace JabyEngine {
|
||||||
Off = 1
|
Off = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Command {
|
__declare_io_type(DisplayMode, uint32_t,
|
||||||
struct GP0 : public ComplexBitMap<uint32_t> {
|
enum struct TVEncoding {
|
||||||
|
NTSC = 0,
|
||||||
static constexpr GP0 QuickFill(GPU::Color24 color) {
|
PAL = 1,
|
||||||
return {(0x02 << 24) | color.raw()};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP0 CPU2VRAM_Blitting() {
|
|
||||||
return {(0b101u << 29)};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP0 DrawAreaTemplate(uint8_t code, uint16_t x, uint16_t y) {
|
|
||||||
constexpr auto Command = BitRange<uint32_t>::from_to(24, 31);
|
|
||||||
constexpr auto Y = BitRange<uint32_t>::from_to(10, 18);
|
|
||||||
constexpr auto X = BitRange<uint32_t>::from_to(0, 9);
|
|
||||||
|
|
||||||
return {GP0::with(Command.with(code), Y.with(y), X.with(x))};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP0 DrawAreaTopLeft(uint16_t x, uint16_t y) {
|
|
||||||
return DrawAreaTemplate(0xE3, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP0 DrawAreaBottomRight(uint16_t x, uint16_t y) {
|
|
||||||
return DrawAreaTemplate(0xE4, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP0 TopLeftPosition(uint16_t x, uint16_t y) {
|
|
||||||
return {static_cast<uint32_t>((y << 16u) | x)};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP0 WidthHeight(uint16_t w, uint16_t h) {
|
|
||||||
return {static_cast<uint32_t>((h << 16u) | w)};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GP1 : public ComplexBitMap<uint32_t> {
|
static constexpr auto HorizontalResolution368 = Bit(6);
|
||||||
|
static constexpr auto VerticalInterlace = Bit(5);
|
||||||
|
static constexpr auto DisplayAreaColorDepth = BitRange::from_to(4, 4);
|
||||||
|
static constexpr auto VideoMode = BitRange::from_to(3, 3);
|
||||||
|
static constexpr auto VerticalResolution = BitRange::from_to(2, 2);
|
||||||
|
static constexpr auto HorizontalResolution = BitRange::from_to(0, 1);
|
||||||
|
|
||||||
|
static constexpr Self PAL() {
|
||||||
|
return Self::from(
|
||||||
|
HorizontalResolution.with(GPU_IO::HorizontalResolution::$320),
|
||||||
|
VerticalResolution.with(GPU_IO::VerticalResolution::$240),
|
||||||
|
VideoMode.with(TVEncoding::PAL),
|
||||||
|
DisplayAreaColorDepth.with(GPU_IO::DisplayAreaColorDepth::$15bit)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr Self NTSC() {
|
||||||
|
return Self::from(
|
||||||
|
HorizontalResolution.with(GPU_IO::HorizontalResolution::$320),
|
||||||
|
VerticalResolution.with(GPU_IO::VerticalResolution::$240),
|
||||||
|
VideoMode.with(TVEncoding::NTSC),
|
||||||
|
DisplayAreaColorDepth.with(GPU_IO::DisplayAreaColorDepth::$15bit)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
__declare_io_type(GP0, uint32_t,
|
||||||
|
);
|
||||||
|
|
||||||
|
__declare_io_type(GP1, uint32_t,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
struct Command {
|
||||||
|
struct Helper {
|
||||||
|
static constexpr GP0_t DrawAreaTemplate(uint8_t code, uint16_t x, uint16_t y) {
|
||||||
|
constexpr auto Command = BitRange::from_to(24, 31);
|
||||||
|
constexpr auto Y = BitRange::from_to(10, 18);
|
||||||
|
constexpr auto X = BitRange::from_to(0, 9);
|
||||||
|
|
||||||
|
return GP0_t::from(Command.with(code), Y.with(y), X.with(x));
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr uint32_t construct_cmd(uint8_t cmd, uint32_t value) {
|
static constexpr uint32_t construct_cmd(uint8_t cmd, uint32_t value) {
|
||||||
return ((cmd << 24) | value);
|
return ((cmd << 24) | value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr GP1 Reset() {
|
|
||||||
return {0};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP1 ResetCMDBufer() {
|
|
||||||
return {construct_cmd(0x01, 0)};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP1 SetDisplayState(DisplayState state) {
|
|
||||||
return {construct_cmd(0x03, static_cast<uint32_t>(state))};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP1 DMADirection(DMADirection dir) {
|
|
||||||
return {construct_cmd(0x04, static_cast<uint32_t>(dir))};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP1 DisplayArea(uint16_t x, uint16_t y) {
|
|
||||||
constexpr auto X = BitRange<uint32_t>::from_to(0, 9);
|
|
||||||
constexpr auto Y = BitRange<uint32_t>::from_to(10, 18);
|
|
||||||
|
|
||||||
return {construct_cmd(0x05, ComplexBitMap<uint32_t>::with(X.with(x), Y.with(y)).raw)};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP1 HorizontalDisplayRange(uint32_t x1, uint32_t x2) {
|
|
||||||
constexpr auto X1 = BitRange<uint32_t>::from_to(0, 11);
|
|
||||||
constexpr auto X2 = BitRange<uint32_t>::from_to(12, 23);
|
|
||||||
|
|
||||||
return {construct_cmd(0x06, ComplexBitMap<uint32_t>::with(X1.with(x1), X2.with(x2)).raw)};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP1 VerticalDisplayRange(uint32_t y1, uint32_t y2) {
|
|
||||||
constexpr auto Y1 = BitRange<uint32_t>::from_to(0, 9);
|
|
||||||
constexpr auto Y2 = BitRange<uint32_t>::from_to(10, 19);
|
|
||||||
|
|
||||||
return {construct_cmd(0x07, ComplexBitMap<uint32_t>::with(Y1.with(y1), Y2.with(y2)).raw)};
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr GP1 DisplayMode(uint32_t mode) {
|
|
||||||
return {construct_cmd(0x08, mode)};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr GP0_t QuickFill(GPU::Color24 color) {
|
||||||
|
return {(0x02 << 24) | color.raw()};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP0_t CPU2VRAM_Blitting() {
|
||||||
|
return {(0b101u << 29)};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP0_t DrawAreaTopLeft(uint16_t x, uint16_t y) {
|
||||||
|
return Helper::DrawAreaTemplate(0xE3, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP0_t DrawAreaBottomRight(uint16_t x, uint16_t y) {
|
||||||
|
return Helper::DrawAreaTemplate(0xE4, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP0_t TopLeftPosition(uint16_t x, uint16_t y) {
|
||||||
|
return {static_cast<uint32_t>((y << 16u) | x)};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP0_t WidthHeight(uint16_t w, uint16_t h) {
|
||||||
|
return {static_cast<uint32_t>((h << 16u) | w)};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP1_t Reset() {
|
||||||
|
return {0};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP1_t ResetCMDBufer() {
|
||||||
|
return {Helper::construct_cmd(0x01, 0)};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP1_t SetDisplayState(DisplayState state) {
|
||||||
|
return {Helper::construct_cmd(0x03, static_cast<uint32_t>(state))};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP1_t DMADirection(DMADirection dir) {
|
||||||
|
return {Helper::construct_cmd(0x04, static_cast<uint32_t>(dir))};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP1_t DisplayArea(uint16_t x, uint16_t y) {
|
||||||
|
constexpr auto X = BitRange::from_to(0, 9);
|
||||||
|
constexpr auto Y = BitRange::from_to(10, 18);
|
||||||
|
|
||||||
|
return {Helper::construct_cmd(0x05, X.as_value(x) | Y.as_value(y))};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP1_t HorizontalDisplayRange(uint32_t x1, uint32_t x2) {
|
||||||
|
constexpr auto X1 = BitRange::from_to(0, 11);
|
||||||
|
constexpr auto X2 = BitRange::from_to(12, 23);
|
||||||
|
|
||||||
|
return {Helper::construct_cmd(0x06, X1.as_value(x1) | X2.as_value(x2))};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP1_t VerticalDisplayRange(uint32_t y1, uint32_t y2) {
|
||||||
|
constexpr auto Y1 = BitRange::from_to(0, 9);
|
||||||
|
constexpr auto Y2 = BitRange::from_to(10, 19);
|
||||||
|
|
||||||
|
return {Helper::construct_cmd(0x07, Y1.as_value(y1) | Y2.as_value(y2))};
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr GP1_t DisplayMode(DisplayMode_t mode) {
|
||||||
|
return {Helper::construct_cmd(0x08, mode)};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GPUStatusRegister : public ComplexBitMap<uint32_t> {
|
__declare_io_type(GPUSTAT, uint32_t,
|
||||||
static constexpr auto DrawingOddLinesInterlaced = Bit<uint32_t>(31);
|
static constexpr auto DrawingOddLinesInterlaced = Bit(31);
|
||||||
static constexpr auto DMADirectionValue = BitRange<DMADirection>::from_to(29, 30);
|
static constexpr auto DMADirectionValue = BitRange::from_to(29, 30);
|
||||||
static constexpr auto DMAReady = Bit<uint32_t>(28);
|
static constexpr auto DMAReady = Bit(28);
|
||||||
static constexpr auto VRAMtoCPUtransferReay = Bit<uint32_t>(27);
|
static constexpr auto VRAMtoCPUtransferReay = Bit(27);
|
||||||
static constexpr auto GP0ReadyForCMD = Bit<uint32_t>(26);
|
static constexpr auto GP0ReadyForCMD = Bit(26);
|
||||||
static constexpr auto FifoNotFull = Bit<uint32_t>(25); // Only for Fifo
|
static constexpr auto FifoNotFull = Bit(25); // Only for Fifo
|
||||||
static constexpr auto InterruptRequest = Bit<uint32_t>(24);
|
static constexpr auto InterruptRequest = Bit(24);
|
||||||
static constexpr auto DisplayDisabled = Bit<uint32_t>(23);
|
static constexpr auto DisplayDisabled = Bit(23);
|
||||||
static constexpr auto VerticalInterlaceOn = Bit<uint32_t>(22);
|
static constexpr auto VerticalInterlaceOn = Bit(22);
|
||||||
static constexpr auto DisplayAreaColorDepth = BitRange<GPU_IO::DisplayAreaColorDepth>::from_to(21, 21);
|
static constexpr auto DisplayAreaColorDepth = BitRange::from_to(21, 21);
|
||||||
static constexpr auto VideoModePal = Bit<uint32_t>(20);
|
static constexpr auto VideoModePal = Bit(20);
|
||||||
static constexpr auto VerticalResolutionValue = BitRange<VerticalResolution>::from_to(19, 19);
|
static constexpr auto VerticalResolutionValue = BitRange::from_to(19, 19);
|
||||||
static constexpr auto HorizontalResolutionValue = BitRange<HorizontalResolution>::from_to(17, 18);
|
static constexpr auto HorizontalResolutionValue = BitRange::from_to(17, 18);
|
||||||
static constexpr auto HorizontalResolution368 = Bit<uint32_t>(16);
|
static constexpr auto HorizontalResolution368 = Bit(16);
|
||||||
static constexpr auto TexturesDisabled = Bit<uint32_t>(15);
|
static constexpr auto TexturesDisabled = Bit(15);
|
||||||
static constexpr auto NotDrawingMaskedPixels = Bit<uint32_t>(12);
|
static constexpr auto NotDrawingMaskedPixels = Bit(12);
|
||||||
static constexpr auto MaskBitSetDuringDrawEnabled = Bit<uint32_t>(11);
|
static constexpr auto MaskBitSetDuringDrawEnabled = Bit(11);
|
||||||
static constexpr auto DrawingToDisplayAreadAllowed = Bit<uint32_t>(10);
|
static constexpr auto DrawingToDisplayAreadAllowed = Bit(10);
|
||||||
static constexpr auto DitherEnabled = Bit<uint32_t>(9);
|
static constexpr auto DitherEnabled = Bit(9);
|
||||||
static constexpr auto TexturePageColorValue = BitRange<TexturePageColor>::from_to(7, 8);
|
static constexpr auto TexturePageColorValue = BitRange::from_to(7, 8);
|
||||||
static constexpr auto SemiTransparencyValue = BitRange<SemiTransparency>::from_to(5, 6);
|
static constexpr auto SemiTransparencyValue = BitRange::from_to(5, 6);
|
||||||
static constexpr auto TexturePageY = BitRange<uint32_t>::from_to(4, 4); // N*256
|
static constexpr auto TexturePageY = BitRange::from_to(4, 4); // N*256
|
||||||
static constexpr auto TexturePageX = BitRange<uint32_t>::from_to(0, 3); // N*64
|
static constexpr auto TexturePageX = BitRange::from_to(0, 3); // N*64
|
||||||
|
|
||||||
static constexpr auto VerticalResolution480 = Bit<uint32_t>(19);
|
static constexpr auto VerticalResolution480 = Bit(19);
|
||||||
static constexpr auto TexturePageY256 = Bit<uint32_t>(4);
|
static constexpr auto TexturePageY256 = Bit(4);
|
||||||
};
|
);
|
||||||
|
|
||||||
__declare_io_port_global(Command::GP0, GP0, 0x1F801810);
|
typedef volatile uint32_t GPUREAD_v;
|
||||||
__declare_io_port_global(Command::GP1, GP1, 0x1F801814);
|
|
||||||
|
|
||||||
__declare_io_port_global_const_simple(uint32_t, GPUREAD, 0x1F801810);
|
__declare_new_io_port(GP0, 0x1F801810);
|
||||||
__declare_io_port_global_const(GPUStatusRegister, GPUSTAT, 0x1F801814);
|
__declare_new_io_port(GP1, 0x1F801814);
|
||||||
|
|
||||||
|
__declare_new_const_io_port(GPUREAD, 0x1F801810);
|
||||||
|
__declare_new_const_io_port(GPUSTAT, 0x1F801814);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //!__JABYENGINE_GPU_IO_HPP__
|
#endif //!__JABYENGINE_GPU_IO_HPP__
|
|
@ -4,42 +4,42 @@
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
struct Interrupt {
|
struct Interrupt {
|
||||||
static constexpr auto VBlank = Bit<uint32_t>(0);
|
static constexpr auto VBlank = Bit(0);
|
||||||
static constexpr auto GPU = Bit<uint32_t>(1);
|
static constexpr auto GPU = Bit(1);
|
||||||
static constexpr auto CDROM = Bit<uint32_t>(2);
|
static constexpr auto CDROM = Bit(2);
|
||||||
static constexpr auto DMA = Bit<uint32_t>(3);
|
static constexpr auto DMA = Bit(3);
|
||||||
static constexpr auto Timer0 = Bit<uint32_t>(4);
|
static constexpr auto Timer0 = Bit(4);
|
||||||
static constexpr auto Timer1 = Bit<uint32_t>(5);
|
static constexpr auto Timer1 = Bit(5);
|
||||||
static constexpr auto Timer2 = Bit<uint32_t>(6);
|
static constexpr auto Timer2 = Bit(6);
|
||||||
static constexpr auto Periphery = Bit<uint32_t>(7);
|
static constexpr auto Periphery = Bit(7);
|
||||||
static constexpr auto SIO = Bit<uint32_t>(8);
|
static constexpr auto SIO = Bit(8);
|
||||||
static constexpr auto SPU = Bit<uint32_t>(9);
|
static constexpr auto SPU = Bit(9);
|
||||||
static constexpr auto Controller = Bit<uint32_t>(10);
|
static constexpr auto Controller = Bit(10);
|
||||||
static constexpr auto LightPen = Controller;
|
static constexpr auto LightPen = Controller;
|
||||||
|
|
||||||
typedef struct Status : public ComplexBitMap<uint32_t> {
|
__declare_io_type(Status, uint32_t,
|
||||||
} Status_t;
|
);
|
||||||
|
|
||||||
typedef struct Mask : public ComplexBitMap<uint32_t> {
|
__declare_io_type(Mask, uint32_t,
|
||||||
} Mask_t;
|
);
|
||||||
|
|
||||||
__declare_io_port_member(Status_t, Status, 0x1F801070);
|
__declare_new_io_port(Status, 0x1F801070);
|
||||||
__declare_io_port_member(Mask_t, Mask, 0x1F801074);
|
__declare_new_io_port(Mask, 0x1F801074);
|
||||||
|
|
||||||
static bool is_irq(Bit<uint32_t> irq) {
|
static bool is_irq(Bit irq) {
|
||||||
return Status.read().is_bit_set(irq);
|
return Status.is_set(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ack_irq(Bit<uint32_t> irq) {
|
static void ack_irq(Bit irq) {
|
||||||
Status.write({Status.read().clear_bit(irq)});
|
Status.clear(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_irq(Bit<uint32_t> irq) {
|
static void disable_irq(Bit irq) {
|
||||||
Mask.write({Mask.read().clear_bit(irq)});
|
Mask.clear(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enable_irq(Bit<uint32_t> irq) {
|
static void enable_irq(Bit irq) {
|
||||||
Mask.write({Mask.read().set_bit(irq)});
|
Mask.set(irq);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +1,124 @@
|
||||||
#ifndef __JABYENGINE_IOPORT_HPP__
|
#ifndef __JABYENGINE_IOPORT_HPP__
|
||||||
#define __JABYENGINE_IOPORT_HPP__
|
#define __JABYENGINE_IOPORT_HPP__
|
||||||
#include "../../Auxiliary/complex_bitmap.hpp"
|
#include "../../Auxiliary/types.hpp"
|
||||||
|
#include "../../Auxiliary/bits.hpp"
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
template<typename T>
|
namespace IOPort {
|
||||||
struct VolatilePOD {
|
struct IOValueType {
|
||||||
volatile T raw;
|
template<typename T>
|
||||||
|
struct Normal {
|
||||||
|
typedef T Value;
|
||||||
|
typedef T UnderlyingValue;
|
||||||
|
};
|
||||||
|
|
||||||
constexpr T read() const {
|
template<typename T>
|
||||||
return this->raw;
|
struct Volatile {
|
||||||
|
typedef volatile T Value;
|
||||||
|
typedef T UnderlyingValue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace IOAdress {
|
||||||
|
constexpr uintptr_t patch_adr(uintptr_t adr) {
|
||||||
|
constexpr uintptr_t Mask = 0xF0000000;
|
||||||
|
constexpr uintptr_t Base = 0x10000000; // We might want to change this later to 0xB0000000 for caching and stuff (More research needed)
|
||||||
|
|
||||||
|
return (Base + (adr & ~Mask));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void write(T value) {
|
#define __declare_new_named_io_port(type, name, adr) \
|
||||||
this->raw = value;
|
static inline auto& name = *reinterpret_cast<type##_v*>(IOAdress::patch_adr(adr))
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// For use with ComplexBitMaps or what else satisfies this API
|
#define __declare_new_io_port(name, adr) \
|
||||||
template<typename T>
|
__declare_new_named_io_port(name, name, adr)
|
||||||
struct VolatileBitMapPOD {
|
|
||||||
typedef typename T::UnderlyingType Raw;
|
|
||||||
|
|
||||||
VolatilePOD<Raw> pod;
|
#define __declare_new_const_io_port(name, adr) \
|
||||||
|
__declare_new_named_io_port(const name, name, adr)
|
||||||
|
|
||||||
|
#define __declare_new_io_port_array(name, adr, size) \
|
||||||
|
static inline auto& name = reinterpret_cast<name##_v(&)[size]>(*reinterpret_cast<name##_v*>(adr))
|
||||||
|
|
||||||
constexpr Raw read_raw() const {
|
// We need this construct to ensure the types end up being a POD - Inheritance doesn't qualify for a POD
|
||||||
return this->pod.read();
|
#define __declare_io_type(name, type, ...) \
|
||||||
}
|
template<template<typename> typename T> \
|
||||||
|
struct name##_io_base { \
|
||||||
constexpr T read() const {
|
typedef T<type>::UnderlyingValue UnderlyingValue; \
|
||||||
return T{this->pod.read()};
|
typedef name##_io_base Self; \
|
||||||
}
|
\
|
||||||
|
T<type>::Value raw_value = 0; \
|
||||||
constexpr Raw read(const BitRange<Raw>& range) const {
|
\
|
||||||
return VolatileBitMapPOD<T>::read().get_value(range);
|
__VA_ARGS__ \
|
||||||
}
|
\
|
||||||
|
template<typename...ARGS> \
|
||||||
constexpr void write_raw(Raw value) {
|
static constexpr Self from(const ARGS&...args) { \
|
||||||
this->pod.write(value);
|
return Self().set_va(args...); \
|
||||||
}
|
} \
|
||||||
|
\
|
||||||
constexpr void write(const T& value) {
|
constexpr Self& set(Bit bit) { \
|
||||||
this->pod.write(static_cast<Raw>(value));
|
this->raw_value = bit::set(this->raw_value, bit); \
|
||||||
}
|
return *this; \
|
||||||
|
} \
|
||||||
constexpr void write(const BitRangeValue<Raw>& value) {
|
\
|
||||||
VolatileBitMapPOD<T>::write(T{T::with(value)});
|
constexpr Self& set(ClearBit bit) { \
|
||||||
}
|
this->raw_value = bit::set(this->raw_value, bit); \
|
||||||
};
|
return *this; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
constexpr Self& set(BitRange bits, UnderlyingValue value) { \
|
||||||
|
this->raw_value = bit::value::set_normalized(this->raw_value, bits, value); \
|
||||||
|
return *this; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
template<typename S> \
|
||||||
|
constexpr Self& set(const BitRange::RangeValuePair<S>& value) { \
|
||||||
|
this->raw_value = bit::value::set_normalized(this->raw_value, value); \
|
||||||
|
return *this; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
template<typename S> \
|
||||||
|
constexpr Self& set_va(const S& head) { \
|
||||||
|
return this->set(head); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
template<typename S, typename...ARGS> \
|
||||||
|
constexpr Self& set_va(const S& head, const ARGS&...tail) { \
|
||||||
|
return this->set(head).set_va(tail...); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
constexpr UnderlyingValue get(BitRange bits) const { \
|
||||||
|
return bit::value::get_normalized(this->raw_value, bits.pos, bits.length); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
constexpr Self& clear(Bit bit) { \
|
||||||
|
this->raw_value = bit::clear(this->raw_value, bit); \
|
||||||
|
return *this; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
constexpr bool is_set(Bit bit) const { \
|
||||||
|
return bit::is_set(this->raw_value, bit); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
constexpr void operator=(UnderlyingValue value) { \
|
||||||
|
this->raw_value = value; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
constexpr operator UnderlyingValue() const { \
|
||||||
|
return this->raw_value; \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
typedef name##_io_base<IOPort::IOValueType::Volatile> name##_v; \
|
||||||
|
typedef name##_io_base<IOPort::IOValueType::Normal> name##_t
|
||||||
|
|
||||||
struct __no_align ubus32_t {
|
struct __no_align ubus32_t {
|
||||||
typedef ComplexBitMap<uint16_t> Base16;
|
__declare_io_type(uint16_t, uint16_t,);
|
||||||
|
uint16_t_v low;
|
||||||
|
uint16_t_v high;
|
||||||
|
|
||||||
VolatileBitMapPOD<Base16> low;
|
constexpr ubus32_t(uint32_t value) : low{0}, high{0} {
|
||||||
VolatileBitMapPOD<Base16> high;
|
|
||||||
|
|
||||||
constexpr ubus32_t(uint32_t value) {
|
|
||||||
*this = value;
|
*this = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,34 +127,18 @@ namespace JabyEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr operator uint32_t() const {
|
constexpr operator uint32_t() const {
|
||||||
return ((this->high.read_raw() << 16) | this->low.read_raw());
|
const uint32_t high = this->high;
|
||||||
|
const uint32_t low = this->low;
|
||||||
|
|
||||||
|
return ((high << 16) | low);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ubus32_t& operator=(uint32_t value) {
|
constexpr ubus32_t& operator=(uint32_t value) {
|
||||||
this->low.write_raw(value & 0xFFFF);
|
this->low = (value & 0xFFFF);
|
||||||
this->high.write_raw(value >> 16);
|
this->high = (value >> 16);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static constexpr uintptr_t IO_Base_Mask = 0xF0000000;
|
|
||||||
static constexpr uintptr_t IO_Base_Adr = 0x10000000;
|
|
||||||
|
|
||||||
#define __io_port_adr(adr) (IO_Base_Adr + (adr & ~IO_Base_Mask))
|
|
||||||
#define __cast_io_adr_with_type(cv, type, name, adr) static __always_inline cv auto& name = *reinterpret_cast<type*>(__io_port_adr(adr))
|
|
||||||
|
|
||||||
|
|
||||||
#define __declare_io_port_global(type, name, adr) __cast_io_adr_with_type(, VolatileBitMapPOD<type>, name, adr)
|
|
||||||
#define __declare_io_port_global_const(type, name, adr) __cast_io_adr_with_type(const, VolatileBitMapPOD<type>, name, adr)
|
|
||||||
#define __declare_io_port_global_simple(type, name, adr) __cast_io_adr_with_type(, VolatilePOD<type>, name, adr)
|
|
||||||
#define __declare_io_port_global_const_simple(type, name, adr) __cast_io_adr_with_type(const, VolatilePOD<type>, name, adr)
|
|
||||||
|
|
||||||
#define __declare_io_port_member(type, name, adr) __cast_io_adr_with_type(inline, VolatileBitMapPOD<type>, name, adr)
|
|
||||||
#define __declare_io_port_member_const(type, name, adr) __cast_io_adr_with_type(const inline, VolatileBitMapPOD<type>, name, adr)
|
|
||||||
#define __declare_io_port_member_simple(type, name, adr) __cast_io_adr_with_type(inline, VolatilePOD<type>, name, adr)
|
|
||||||
#define __declare_io_port_member_const_simple(type, name, adr) __cast_io_adr_with_type(const inline, VolatilePOD<type>, name, adr)
|
|
||||||
|
|
||||||
#define __declare_io_port_global_array(type, name, adr, size) static __always_inline auto& name = reinterpret_cast<type(&)[size]>(*reinterpret_cast<type*>(__io_port_adr(adr)))
|
|
||||||
#define __declare_io_port_global_struct(type, name, adr) static __always_inline auto& name = *reinterpret_cast<type*>(__io_port_adr(adr))
|
|
||||||
}
|
}
|
||||||
#endif //!__JABYENGINE_IOPORT_HPP__
|
#endif //!__JABYENGINE_IOPORT_HPP__
|
|
@ -4,20 +4,20 @@
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace Memory_IO {
|
namespace Memory_IO {
|
||||||
struct COM_DELAY {
|
__declare_io_type(COM_DELAY, uint32_t,
|
||||||
typedef uint32_t Type;
|
void setup() {
|
||||||
|
this->raw_value = 0x1325;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
static constexpr uint32_t SetupValue = 0x1325;
|
__declare_io_type(CD_DELAY, uint32_t,
|
||||||
};
|
void setup() {
|
||||||
|
this->raw_value = 0x20943;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
struct CD_DELAY {
|
__declare_new_io_port(COM_DELAY, 0x1F801020);
|
||||||
typedef uint32_t Type;
|
__declare_new_io_port(CD_DELAY, 0x1F801018);
|
||||||
|
|
||||||
static constexpr uint32_t SetupValue = 0x20943;
|
|
||||||
};
|
|
||||||
|
|
||||||
__declare_io_port_global_simple(COM_DELAY::Type, COM_DELAY, 0x1F801020);
|
|
||||||
__declare_io_port_global_simple(CD_DELAY::Type, CD_DELAY, 0x1F801018);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,60 +25,64 @@ namespace JabyEngine {
|
||||||
//0..3 = +7, +6, +5, +4 or -6, -7, -6, -5
|
//0..3 = +7, +6, +5, +4 or -6, -7, -6, -5
|
||||||
typedef uint8_t Step;
|
typedef uint8_t Step;
|
||||||
|
|
||||||
typedef int16_t SimpleVolume;
|
typedef int16_t SimpleVolume;
|
||||||
|
typedef volatile int16_t SimpleVolume_v;
|
||||||
|
|
||||||
struct SampleRate : public ComplexBitMap<uint16_t> {
|
typedef volatile uint16_t Adr_v;
|
||||||
static constexpr SampleRate from_HZ(double freq) {
|
typedef volatile uint16_t DataTransferControl_v;
|
||||||
|
|
||||||
|
__declare_io_type(SampleRate, uint16_t,
|
||||||
|
static constexpr Self from_HZ(double freq) {
|
||||||
//4096 == 44100Hz
|
//4096 == 44100Hz
|
||||||
constexpr double Base = (4096.0 / 44100.0);
|
constexpr double Base = (4096.0 / 44100.0);
|
||||||
|
|
||||||
return {static_cast<uint16_t>((freq*Base))};
|
return {static_cast<uint16_t>((freq*Base))};
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
|
|
||||||
struct SweepVolume : public ComplexBitMap<int16_t> {
|
__declare_io_type(SweepVolume, int16_t,
|
||||||
// For Volume Mode
|
// For Volume Mode
|
||||||
static constexpr auto SweepEnable = Bit<int16_t>(15);
|
static constexpr auto SweepEnable = Bit(15);
|
||||||
static constexpr auto VolumeEnable = !SweepEnable;
|
static constexpr auto VolumeEnable = !SweepEnable;
|
||||||
static constexpr auto Volume = BitRange<int16_t>::from_to(0, 14);
|
static constexpr auto Volume = BitRange::from_to(0, 14);
|
||||||
|
|
||||||
// For Sweep Mode
|
// For Sweep Mode
|
||||||
static constexpr auto SweepMode = Bit<Mode>(14);
|
static constexpr auto SweepMode = Bit(14);
|
||||||
static constexpr auto SweepDirection = Bit<Direction>(13);
|
static constexpr auto SweepDirection = Bit(13);
|
||||||
static constexpr auto SweepPhase = Bit<Phase>(12);
|
static constexpr auto SweepPhase = Bit(12);
|
||||||
static constexpr auto SweepShift = BitRange<Shift>::from_to(2, 6);
|
static constexpr auto SweepShift = BitRange::from_to(2, 6);
|
||||||
static constexpr auto SweepStep = BitRange<Step>::from_to(0, 1);
|
static constexpr auto SweepStep = BitRange::from_to(0, 1);
|
||||||
|
);
|
||||||
|
|
||||||
|
__declare_io_type(SR, uint16_t,
|
||||||
|
static constexpr auto SustainMode = Bit(31 - 16);
|
||||||
|
static constexpr auto SustainDirection = Bit(30 - 16);
|
||||||
|
static constexpr auto SustainShift = BitRange::from_to((24 - 16), (28 - 16));
|
||||||
|
static constexpr auto SustainStep = BitRange::from_to((22 - 16), (23 - 16));
|
||||||
|
static constexpr auto ReleaseMode = Bit(21 - 16);
|
||||||
|
static constexpr auto ReleaseShift = BitRange::from_to((16 - 16), (20 - 16));
|
||||||
|
);
|
||||||
|
|
||||||
|
__declare_io_type(AD, uint16_t,
|
||||||
|
static constexpr auto AttackMode = Bit(15);
|
||||||
|
static constexpr auto AttackShift = BitRange::from_to(10, 14);
|
||||||
|
static constexpr auto AttackStep = BitRange::from_to(8, 9);
|
||||||
|
static constexpr auto DecayShift = BitRange::from_to(4, 7);
|
||||||
|
static constexpr auto SustainLevel = BitRange::from_to(0, 3);
|
||||||
|
);
|
||||||
|
|
||||||
|
struct __no_align Voice_v {
|
||||||
|
SweepVolume_v volumeLeft; //Offset: 0x0
|
||||||
|
SweepVolume_v volumeRight; //Offset: 0x2
|
||||||
|
SampleRate_v sampleRate; //Offset: 0x4;
|
||||||
|
Adr_v adr; //Offset: 0x6
|
||||||
|
AD_v ad; //Offset: 0x8
|
||||||
|
SR_v sr; //Offset: 0xA
|
||||||
|
SimpleVolume_v currentVolume; //Offset: 0xC
|
||||||
|
Adr_v repeatAdr; //Offset: 0xE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SR : public ComplexBitMap<uint16_t> {
|
__declare_io_type(ControlRegister, uint16_t,
|
||||||
static constexpr auto SustainMode = Bit<Mode>(31 - 16);
|
|
||||||
static constexpr auto SustainDirection = Bit<Direction>(30 - 16);
|
|
||||||
static constexpr auto SustainShift = BitRange<Shift>::from_to((24 - 16), (28 - 16));
|
|
||||||
static constexpr auto SustainStep = BitRange<Step>::from_to((22 - 16), (23 - 16));
|
|
||||||
static constexpr auto ReleaseMode = Bit<Mode>(21 - 16);
|
|
||||||
static constexpr auto ReleaseShift = BitRange<Shift>::from_to((16 - 16), (20 - 16));
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AD : public ComplexBitMap<uint16_t> {
|
|
||||||
static constexpr auto AttackMode = Bit<Mode>(15);
|
|
||||||
static constexpr auto AttackShift = BitRange<Shift>::from_to(10, 14);
|
|
||||||
static constexpr auto AttackStep = BitRange<Step>::from_to(8, 9);
|
|
||||||
static constexpr auto DecayShift = BitRange<Shift>::from_to(4, 7);
|
|
||||||
static constexpr auto SustainLevel = BitRange<uint16_t>::from_to(0, 3);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct __no_align Voice {
|
|
||||||
VolatileBitMapPOD<SweepVolume> volumeLeft; //Offset: 0x0
|
|
||||||
VolatileBitMapPOD<SweepVolume> volumeRight; //Offset: 0x2
|
|
||||||
VolatileBitMapPOD<SampleRate> sampleRate; //Offset: 0x4;
|
|
||||||
VolatilePOD<uint16_t> adr; //Offset: 0x6
|
|
||||||
VolatileBitMapPOD<AD> ad; //Offset: 0x8
|
|
||||||
VolatileBitMapPOD<SR> sr; //Offset: 0xA
|
|
||||||
VolatilePOD<SimpleVolume> currentVolume; //Offset: 0xC
|
|
||||||
VolatilePOD<uint16_t> repeatAdr; //Offset: 0xE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ControlRegister : public ComplexBitMap<uint16_t> {
|
|
||||||
enum RAMTransferMode {
|
enum RAMTransferMode {
|
||||||
Stop = 0,
|
Stop = 0,
|
||||||
ManualWrite = 1,
|
ManualWrite = 1,
|
||||||
|
@ -86,69 +90,71 @@ namespace JabyEngine {
|
||||||
DMARead = 3
|
DMARead = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr auto Enable = Bit<uint16_t>(15);
|
static constexpr auto Enable = Bit(15);
|
||||||
static constexpr auto Unmute = Bit<uint16_t>(14);
|
static constexpr auto Unmute = Bit(14);
|
||||||
static constexpr auto NoiseFrequcenyShift = BitRange<Shift>::from_to(10, 13);
|
static constexpr auto NoiseFrequcenyShift = BitRange::from_to(10, 13);
|
||||||
static constexpr auto NoiseFrequcenyStep = BitRange<Step>::from_to(8, 9);
|
static constexpr auto NoiseFrequcenyStep = BitRange::from_to(8, 9);
|
||||||
static constexpr auto ReverbMasterEnable = Bit<uint16_t>(7);
|
static constexpr auto ReverbMasterEnable = Bit(7);
|
||||||
static constexpr auto IRQ9Enable = Bit<uint16_t>(6);
|
static constexpr auto IRQ9Enable = Bit(6);
|
||||||
static constexpr auto TransferMode = BitRange<RAMTransferMode>::from_to(4, 5);
|
static constexpr auto TransferMode = BitRange::from_to(4, 5);
|
||||||
static constexpr auto ExternalAudioReverb = Bit<uint16_t>(3);
|
static constexpr auto ExternalAudioReverb = Bit(3);
|
||||||
static constexpr auto CDAudioReverb = Bit<uint16_t>(2);
|
static constexpr auto CDAudioReverb = Bit(2);
|
||||||
static constexpr auto ExternalAudioEnable = Bit<uint16_t>(1);
|
static constexpr auto ExternalAudioEnable = Bit(1);
|
||||||
static constexpr auto CDAudioEnable = Bit<uint16_t>(0);
|
static constexpr auto CDAudioEnable = Bit(0);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct PitchModFlags : public ComplexBitMap<uint16_t> {
|
__declare_io_type(PMON, uint16_t,
|
||||||
static constexpr BitRange<uint16_t> EnableBits = BitRange<uint16_t>::from_to(1, 23);
|
static constexpr auto EnableBits = BitRange::from_to(1, 23);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct NoiseGenerator : public ComplexBitMap<uint16_t> {
|
__declare_io_type(NON, uint16_t,
|
||||||
static constexpr BitRange<uint16_t> NoiseBits = BitRange<uint16_t>::from_to(0, 23);
|
static constexpr auto NoiseBits = BitRange::from_to(0, 23);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct EchoOn : public ComplexBitMap<uint16_t> {
|
__declare_io_type(EON, uint16_t,
|
||||||
static constexpr BitRange<uint16_t> EchoBits = BitRange<uint16_t>::from_to(0, 23);
|
static constexpr auto EchoBits = BitRange::from_to(0, 23);
|
||||||
};
|
);
|
||||||
|
|
||||||
static constexpr size_t VoiceCount = 24;
|
static constexpr size_t VoiceCount = 24;
|
||||||
|
|
||||||
struct Key {
|
struct Key {
|
||||||
__cast_io_adr_with_type(inline, ubus32_t, On, 0x1F801D88);
|
typedef ubus32_t ubus32_v;
|
||||||
__cast_io_adr_with_type(inline, ubus32_t, Off, 0x1F801D8C);
|
|
||||||
__cast_io_adr_with_type(inline, ubus32_t, Status, 0x1F801D9C);
|
__declare_new_named_io_port(ubus32, On, 0x1F801D88);
|
||||||
|
__declare_new_named_io_port(ubus32, Off, 0x1F801D8C);
|
||||||
|
__declare_new_named_io_port(ubus32, Status, 0x1F801D9C);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MainVolume {
|
struct MainVolume {
|
||||||
__declare_io_port_member(SweepVolume, Left, 0x1F801D80);
|
__declare_new_named_io_port(SweepVolume, Left, 0x1F801D80);
|
||||||
__declare_io_port_member(SweepVolume, Right, 0x1F801D82);
|
__declare_new_named_io_port(SweepVolume, Right, 0x1F801D82);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CDVolume {
|
struct CDVolume {
|
||||||
__declare_io_port_member_simple(SimpleVolume, Left, 0x1F801DB0);
|
__declare_new_named_io_port(SimpleVolume, Left, 0x1F801DB0);
|
||||||
__declare_io_port_member_simple(SimpleVolume, Right, 0x1F801DB2);
|
__declare_new_named_io_port(SimpleVolume, Right, 0x1F801DB2);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExternalAudioInputVolume {
|
struct ExternalAudioInputVolume {
|
||||||
__declare_io_port_member_simple(SimpleVolume, Left, 0x1F801DB4);
|
__declare_new_named_io_port(SimpleVolume, Left, 0x1F801DB4);
|
||||||
__declare_io_port_member_simple(SimpleVolume, Right, 0x1F801DB6);
|
__declare_new_named_io_port(SimpleVolume, Right, 0x1F801DB6);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Reverb {
|
struct Reverb {
|
||||||
struct Volume {
|
struct Volume {
|
||||||
__declare_io_port_member_simple(SimpleVolume, Left, 0x1F801D84);
|
__declare_new_named_io_port(SimpleVolume, Left, 0x1F801D84);
|
||||||
__declare_io_port_member_simple(SimpleVolume, Right, 0x1F801D86);
|
__declare_new_named_io_port(SimpleVolume, Right, 0x1F801D86);
|
||||||
};
|
};
|
||||||
__declare_io_port_member_simple(uint16_t, WorkAreaAdr, 0x1F801DA2);
|
__declare_new_named_io_port(Adr, WorkAreaAdr, 0x1F801DA2);
|
||||||
};
|
};
|
||||||
|
|
||||||
__declare_io_port_global(ControlRegister, Control, 0x1F801DAA);
|
__declare_new_io_port(ControlRegister, 0x1F801DAA);
|
||||||
__declare_io_port_global_simple(uint16_t, DataTransferControl, 0x1F801DAC);
|
__declare_new_io_port(DataTransferControl, 0x1F801DAC);
|
||||||
__declare_io_port_global(PitchModFlags, PMON, 0x1F801D90);
|
__declare_new_io_port(PMON, 0x1F801D90);
|
||||||
__declare_io_port_global(NoiseGenerator, NON, 0x1F801D94);
|
__declare_new_io_port(NON, 0x1F801D94);
|
||||||
__declare_io_port_global(EchoOn, EON, 0x1F801D98);
|
__declare_new_io_port(EON, 0x1F801D98);
|
||||||
|
|
||||||
__declare_io_port_global_array(struct Voice, Voice, 0x1F801C00, VoiceCount);
|
__declare_new_io_port_array(Voice, 0x1F801C00, VoiceCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif //!__JABYENGINE_SPU_IO_HPP__
|
#endif //!__JABYENGINE_SPU_IO_HPP__
|
|
@ -4,94 +4,108 @@
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace Timer_IO {
|
namespace Timer_IO {
|
||||||
struct CounterMode : public ComplexBitMap<uint32_t> {
|
__declare_io_type(CounterMode, uint32_t,
|
||||||
static constexpr auto SyncEnable = Bit<uint32_t>(0);
|
static constexpr auto SyncEnable = Bit(0);
|
||||||
static constexpr auto FreeRun = !SyncEnable;
|
static constexpr auto FreeRun = !SyncEnable;
|
||||||
static constexpr auto SyncMode = BitRange<uint32_t>::from_to(1, 2);
|
static constexpr auto SyncMode = BitRange::from_to(1, 2);
|
||||||
static constexpr auto ResetAfterTarget = Bit<uint32_t>(3);
|
static constexpr auto ResetAfterTarget = Bit(3);
|
||||||
static constexpr auto IRQAtTarget = Bit<uint32_t>(4);
|
static constexpr auto IRQAtTarget = Bit(4);
|
||||||
static constexpr auto IRQAtMax = Bit<uint32_t>(5);
|
static constexpr auto IRQAtMax = Bit(5);
|
||||||
static constexpr auto IRQEveryTime = Bit<uint32_t>(6);
|
static constexpr auto IRQEveryTime = Bit(6);
|
||||||
static constexpr auto IRQOneShot = !IRQEveryTime;
|
static constexpr auto IRQOneShot = !IRQEveryTime;
|
||||||
static constexpr auto IRQToggle = Bit<uint32_t>(7);
|
static constexpr auto IRQToggle = Bit(7);
|
||||||
static constexpr auto IRQPulse = !IRQToggle;
|
static constexpr auto IRQPulse = !IRQToggle;
|
||||||
static constexpr auto ClockSource = BitRange<uint32_t>::from_to(8, 9);
|
static constexpr auto ClockSource = BitRange::from_to(8, 9);
|
||||||
static constexpr auto HasIRQRequest = Bit<uint32_t>(10);
|
static constexpr auto HasIRQRequest = Bit(10);
|
||||||
static constexpr auto IsTargetReached = Bit<uint32_t>(11);
|
static constexpr auto IsTargetReached = Bit(11);
|
||||||
static constexpr auto IsMaxReached = Bit<uint32_t>(12);
|
static constexpr auto IsMaxReached = Bit(12);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct CounterTarget : public ComplexBitMap<uint32_t> {
|
__declare_io_type(CounterTarget, uint32_t,
|
||||||
static constexpr auto CounterTargetValue = BitRange<uint32_t>::from_to(0, 15);
|
static constexpr auto CounterTargetValue = BitRange::from_to(0, 15);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct CounterValue : public ComplexBitMap<uint32_t> {
|
__declare_io_type(CounterValue, uint32_t,
|
||||||
static constexpr auto Value = BitRange<uint32_t>::from_to(0, 15);
|
static constexpr auto Value = BitRange::from_to(0, 15);
|
||||||
};
|
);
|
||||||
|
|
||||||
struct __no_align Counter {
|
struct __no_align Counter {
|
||||||
VolatileBitMapPOD<CounterValue> value;
|
CounterValue_v value;
|
||||||
VolatileBitMapPOD<CounterMode> mode;
|
CounterMode_v mode;
|
||||||
VolatileBitMapPOD<CounterTarget> target;
|
CounterTarget_v target;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t _unused;
|
uint32_t _unused;
|
||||||
|
|
||||||
|
public:
|
||||||
|
constexpr uint16_t get_current_value() const {
|
||||||
|
return this->value.get(CounterValue_v::Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void set_target_value(uint16_t value) {
|
||||||
|
this->target.set(CounterTarget_v::CounterTargetValue, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void set_mode(CounterMode_t mode) {
|
||||||
|
this->mode = mode;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr uintptr_t counter_base_adr(size_t ID) {
|
static constexpr uintptr_t counter_base_adr(size_t ID) {
|
||||||
return (0x1F801100 + (ID*0x10));
|
return (0x1F801100 + (ID*0x10));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct __no_align Counter0 : public Counter {
|
struct __no_align Counter0_v : public Counter {
|
||||||
struct SyncMode {
|
struct SyncMode {
|
||||||
static constexpr auto Pause_During_Hblank = CounterMode::SyncMode.with(0);
|
static constexpr auto Pause_During_Hblank = CounterMode_v::SyncMode.with(0u);
|
||||||
static constexpr auto Zero_At_Hblank = CounterMode::SyncMode.with(1);
|
static constexpr auto Zero_At_Hblank = CounterMode_v::SyncMode.with(1u);
|
||||||
static constexpr auto Zero_At_Hblank_Pause_Outside_Hblank = CounterMode::SyncMode.with(2);
|
static constexpr auto Zero_At_Hblank_Pause_Outside_Hblank = CounterMode_v::SyncMode.with(2u);
|
||||||
static constexpr auto Pause_Until_Hblank_Then_Freerun = CounterMode::SyncMode.with(3);
|
static constexpr auto Pause_Until_Hblank_Then_Freerun = CounterMode_v::SyncMode.with(3u);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Source {
|
struct Source {
|
||||||
static constexpr auto System_Clock = CounterMode::ClockSource.with(0);
|
static constexpr auto System_Clock = CounterMode_v::ClockSource.with(0u);
|
||||||
static constexpr auto Dot_Clock = CounterMode::ClockSource.with(1);
|
static constexpr auto Dot_Clock = CounterMode_v::ClockSource.with(1u);
|
||||||
static constexpr auto System_Clock_Too = CounterMode::ClockSource.with(2);
|
static constexpr auto System_Clock_Too = CounterMode_v::ClockSource.with(2u);
|
||||||
static constexpr auto Dot_Clock_Too = CounterMode::ClockSource.with(3);
|
static constexpr auto Dot_Clock_Too = CounterMode_v::ClockSource.with(3u);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __no_align Counter1 : public Counter {
|
struct __no_align Counter1_v : public Counter {
|
||||||
struct SyncMode {
|
struct SyncMode {
|
||||||
static constexpr auto Pause_During_Vblank = CounterMode::SyncMode.with(0);
|
static constexpr auto Pause_During_Vblank = CounterMode_v::SyncMode.with(0u);
|
||||||
static constexpr auto Zero_At_Vblank = CounterMode::SyncMode.with(1);
|
static constexpr auto Zero_At_Vblank = CounterMode_v::SyncMode.with(1u);
|
||||||
static constexpr auto Zero_At_Vblank_Pause_Outside_Vblank = CounterMode::SyncMode.with(2);
|
static constexpr auto Zero_At_Vblank_Pause_Outside_Vblank = CounterMode_v::SyncMode.with(2u);
|
||||||
static constexpr auto Pause_Until_Vblank_Then_Freerun = CounterMode::SyncMode.with(3);
|
static constexpr auto Pause_Until_Vblank_Then_FreeRun = CounterMode_v::SyncMode.with(3u);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Source {
|
struct Source {
|
||||||
static constexpr auto System_Clock = CounterMode::ClockSource.with(0);
|
static constexpr auto System_Clock = CounterMode_v::ClockSource.with(0u);
|
||||||
static constexpr auto Hblank = CounterMode::ClockSource.with(1);
|
static constexpr auto Hblank = CounterMode_v::ClockSource.with(1u);
|
||||||
static constexpr auto System_Clock_Too = CounterMode::ClockSource.with(2);
|
static constexpr auto System_Clock_Too = CounterMode_v::ClockSource.with(2u);
|
||||||
static constexpr auto Hblank_Too = CounterMode::ClockSource.with(3);
|
static constexpr auto Hblank_Too = CounterMode_v::ClockSource.with(3u);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct __no_align Counter2 : public Counter {
|
struct __no_align Counter2_v : public Counter {
|
||||||
struct SyncMode {
|
struct SyncMode {
|
||||||
static constexpr auto Stop_Counter = CounterMode::SyncMode.with(0);
|
static constexpr auto Stop_Counter = CounterMode_v::SyncMode.with(0u);
|
||||||
static constexpr auto Freerun = CounterMode::SyncMode.with(1);
|
static constexpr auto FreeRun = CounterMode_v::SyncMode.with(1u);
|
||||||
static constexpr auto Freerun_Too = CounterMode::SyncMode.with(2);
|
static constexpr auto FreeRun_Too = CounterMode_v::SyncMode.with(2u);
|
||||||
static constexpr auto Stop_Counter_Too = CounterMode::SyncMode.with(3);
|
static constexpr auto Stop_Counter_Too = CounterMode_v::SyncMode.with(3u);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Source {
|
struct Source {
|
||||||
static constexpr auto System_Clock = CounterMode::ClockSource.with(0);
|
static constexpr auto System_Clock = CounterMode_v::ClockSource.with(0u);
|
||||||
static constexpr auto System_Clock_Too = CounterMode::ClockSource.with(1);
|
static constexpr auto System_Clock_Too = CounterMode_v::ClockSource.with(1u);
|
||||||
static constexpr auto System_Clock_Div_8 = CounterMode::ClockSource.with(2);
|
static constexpr auto System_Clock_Div_8 = CounterMode_v::ClockSource.with(2u);
|
||||||
static constexpr auto System_Clock_Div_8_Too = CounterMode::ClockSource.with(3);
|
static constexpr auto System_Clock_Div_8_Too = CounterMode_v::ClockSource.with(3u);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
__declare_io_port_global_struct(struct Counter0, Counter0, counter_base_adr(0));
|
__declare_new_io_port(Counter0, counter_base_adr(0));
|
||||||
__declare_io_port_global_struct(struct Counter1, Counter1, counter_base_adr(1));
|
__declare_new_io_port(Counter1, counter_base_adr(1));
|
||||||
__declare_io_port_global_struct(struct Counter2, Counter2, counter_base_adr(2));
|
__declare_new_io_port(Counter2, counter_base_adr(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace JabyEngine {
|
||||||
~HighResTime() = delete;
|
~HighResTime() = delete;
|
||||||
|
|
||||||
static TimeStamp get_time_stamp() {
|
static TimeStamp get_time_stamp() {
|
||||||
return TimeStamp(HighResTime::global_counter_10ms, Timer_IO::Counter2.value.read(Timer_IO::CounterValue::Value));
|
return TimeStamp(HighResTime::global_counter_10ms, Timer_IO::Counter2.get_current_value());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif //JABYENGINE_USE_HIGH_PERCISION_TIMER
|
#endif //JABYENGINE_USE_HIGH_PERCISION_TIMER
|
||||||
|
|
|
@ -1,36 +1,9 @@
|
||||||
#ifndef __JABYENGINE__HPP__
|
#ifndef __JABYENGINE__HPP__
|
||||||
#define __JABYENGINE__HPP__
|
#define __JABYENGINE__HPP__
|
||||||
#include "../stdint.h"
|
#include "jabyengine_defines.h"
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
struct NextRoutine {
|
typedef void (*MainRoutine)();
|
||||||
static constexpr uintptr_t OverlayBit = (1 << ((sizeof(uintptr_t)*8) - 2));
|
|
||||||
typedef NextRoutine (*MainRoutine)();
|
|
||||||
|
|
||||||
uintptr_t value;
|
|
||||||
|
|
||||||
constexpr static NextRoutine null() {
|
|
||||||
return {.value = 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
static NextRoutine from(MainRoutine function) {
|
|
||||||
return {.value = reinterpret_cast<uintptr_t>(function)};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool is_overlay() const {
|
|
||||||
return (this->value & OverlayBit);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool is_absolute() const {
|
|
||||||
return !NextRoutine::is_overlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool is_null() const {
|
|
||||||
return this->value == 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef NextRoutine::MainRoutine MainRoutine;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //!__JABYENGINE__HPP__
|
#endif //!__JABYENGINE__HPP__
|
|
@ -3,9 +3,10 @@
|
||||||
#include "jabyengine_config.hpp"
|
#include "jabyengine_config.hpp"
|
||||||
#include "../stddef.h"
|
#include "../stddef.h"
|
||||||
|
|
||||||
#define __keep __attribute__((used))
|
#define __used __attribute__((used))
|
||||||
#define __no_align __attribute__((packed))
|
#define __no_align __attribute__((packed))
|
||||||
#define __no_inline __attribute__((noinline))
|
#define __no_inline __attribute__((noinline))
|
||||||
|
#define __no_return __attribute__((noreturn))
|
||||||
#define __always_inline __attribute__((always_inline))
|
#define __always_inline __attribute__((always_inline))
|
||||||
#define __section(name) __attribute__((section(name)))
|
#define __section(name) __attribute__((section(name)))
|
||||||
#define __collect(...) __VA_ARGS__
|
#define __collect(...) __VA_ARGS__
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
#Add the JabyEngine tools to path
|
||||||
|
export PATH := $(JABY_ENGINE_DIR)/bin/:$(PATH)
|
|
@ -1,5 +1,5 @@
|
||||||
#Add the JabyEngine tools to path
|
SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
|
||||||
export PATH := $(JABY_ENGINE_DIR)/bin/:$(PATH)
|
include $(SELF_DIR)ExportPath.mk
|
||||||
|
|
||||||
#Build architecture/variant string, possible values: x86, armv7le, etc...
|
#Build architecture/variant string, possible values: x86, armv7le, etc...
|
||||||
PLATFORM ?= PSX
|
PLATFORM ?= PSX
|
||||||
|
|
|
@ -7,10 +7,6 @@ include $(AUTO_OVERLAY_DIR)/Overlays.mk
|
||||||
JABY_ENGINE_LIB_DIR = $(JABY_ENGINE_DIR)/lib/PSX-$(BUILD_PROFILE)
|
JABY_ENGINE_LIB_DIR = $(JABY_ENGINE_DIR)/lib/PSX-$(BUILD_PROFILE)
|
||||||
JABY_ENGINE_LIB_NAME = JabyEngine_$(TV_FORMAT)
|
JABY_ENGINE_LIB_NAME = JabyEngine_$(TV_FORMAT)
|
||||||
|
|
||||||
#Bind this to the overlay.json file maybe?
|
|
||||||
BOOT_TYPE = main
|
|
||||||
OBJS += $(JABY_ENGINE_LIB_DIR)/$(BOOT_TYPE)_boot.o
|
|
||||||
|
|
||||||
#Linking rule
|
#Linking rule
|
||||||
$(TARGET).elf: $(OBJS) $(JABY_ENGINE_LIB_DIR)/lib$(JABY_ENGINE_LIB_NAME).a $(AUTO_OVERLAY_DIR)/Overlays.ld
|
$(TARGET).elf: $(OBJS) $(JABY_ENGINE_LIB_DIR)/lib$(JABY_ENGINE_LIB_NAME).a $(AUTO_OVERLAY_DIR)/Overlays.ld
|
||||||
$(LD) -o $(TARGET).elf $(LDFLAGS_all) $(LDFLAGS) $(OBJS) -L$(JABY_ENGINE_LIB_DIR) -l$(JABY_ENGINE_LIB_NAME) $(LIBS)
|
$(LD) -o $(TARGET).elf $(LDFLAGS_all) $(LDFLAGS) $(OBJS) -L$(JABY_ENGINE_LIB_DIR) -l$(JABY_ENGINE_LIB_NAME) $(LIBS)
|
||||||
|
|
|
@ -16,9 +16,7 @@ SRCS += src/syscall_printf.asm
|
||||||
include ../../lib/Makefile
|
include ../../lib/Makefile
|
||||||
LIB_DIR = ../../lib/$(CONFIG_NAME)
|
LIB_DIR = ../../lib/$(CONFIG_NAME)
|
||||||
|
|
||||||
MAIN_BOOT_OBJ = $(filter %/main_boot.o,$(OBJS))
|
MAIN_LIB_OBJS = $(filter-out $(MAIN_BOOT_OBJ) $(OVERLAY_BOOT_OBJ),$(OBJS))
|
||||||
OVERLAY_BOOT_OBJ = $(filter %/overlay_boot.o,$(OBJS))
|
|
||||||
MAIN_LIB_OBJS = $(filter-out $(MAIN_BOOT_OBJ) $(OVERLAY_BOOT_OBJ),$(OBJS))
|
|
||||||
|
|
||||||
#$(info $$var is [${MAIN_BOOT_OBJ}])
|
#$(info $$var is [${MAIN_BOOT_OBJ}])
|
||||||
#$(info $$var2 is [${MAIN_LIB_OBJS}])
|
#$(info $$var2 is [${MAIN_LIB_OBJS}])
|
||||||
|
@ -33,15 +31,8 @@ $(LIB_DIR)/$(ARTIFACT).a: $(TARGET).a
|
||||||
@mkdir -p $(LIB_DIR)
|
@mkdir -p $(LIB_DIR)
|
||||||
cp $(TARGET).a $(LIB_DIR)/$(ARTIFACT).a
|
cp $(TARGET).a $(LIB_DIR)/$(ARTIFACT).a
|
||||||
|
|
||||||
$(LIB_DIR)/$(notdir $(MAIN_BOOT_OBJ)): $(MAIN_BOOT_OBJ)
|
|
||||||
@mkdir -p $(LIB_DIR)
|
|
||||||
cp $(MAIN_BOOT_OBJ) $(LIB_DIR)/$(notdir $(MAIN_BOOT_OBJ))
|
|
||||||
|
|
||||||
$(LIB_DIR)/$(notdir $(OVERLAY_BOOT_OBJ)): $(OVERLAY_BOOT_OBJ)
|
|
||||||
@mkdir -p $(LIB_DIR)
|
|
||||||
cp $(OVERLAY_BOOT_OBJ) $(LIB_DIR)/$(notdir $(OVERLAY_BOOT_OBJ))
|
|
||||||
|
|
||||||
# Improve later
|
# Improve later
|
||||||
|
# rule to make the boot image
|
||||||
$(SPLASH_IMAGE): ressources/Splash.png
|
$(SPLASH_IMAGE): ressources/Splash.png
|
||||||
jaby_engine_fconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@
|
jaby_engine_fconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@
|
||||||
|
|
||||||
|
@ -49,7 +40,7 @@ $(SPLASH_IMAGE_NTSC): ressources/Splash_ntsc.png
|
||||||
jaby_engine_fconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@
|
jaby_engine_fconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@
|
||||||
|
|
||||||
#Rules section for default compilation and linking
|
#Rules section for default compilation and linking
|
||||||
all: $(SPLASH_IMAGE) $(SPLASH_IMAGE_NTSC) $(LIB_DIR)/$(ARTIFACT).a $(LIB_DIR)/$(notdir $(MAIN_BOOT_OBJ)) $(LIB_DIR)/$(notdir $(OVERLAY_BOOT_OBJ))
|
all: $(SPLASH_IMAGE) $(SPLASH_IMAGE_NTSC) $(LIB_DIR)/$(ARTIFACT).a
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr $(SPLASH_IMAGE)
|
rm -fr $(SPLASH_IMAGE)
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
#ifndef __JABYENGINE_CD_INTERNAL_HPP__
|
|
||||||
#define __JABYENGINE_CD_INTERNAL_HPP__
|
|
||||||
#include "cd_types.hpp"
|
|
||||||
#include <PSX/System/IOPorts/cd_io.hpp>
|
|
||||||
|
|
||||||
namespace JabyEngine {
|
|
||||||
namespace CD {
|
|
||||||
namespace internal {
|
|
||||||
extern VolatilePOD<CD_IO::Interrupt::Type> last_interrupt;
|
|
||||||
|
|
||||||
struct Command {
|
|
||||||
static void wait_until(CD_IO::Interrupt::Type irq) {
|
|
||||||
while(last_interrupt.read() != irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename...ARGS>
|
|
||||||
static void send(CD_IO::CommandFifo_t& cmd_fifo, CD_IO::ParameterFifo_t& parameter_fifo, CD_IO::Command::Info cmd, ARGS...args) {
|
|
||||||
while(CD_IO::IndexStatus.read().is_bit_set(CD_IO::IndexStatus::IsTransmissionBusy));
|
|
||||||
|
|
||||||
(parameter_fifo.write(static_cast<uint8_t>(args)), ...);
|
|
||||||
cmd_fifo.write(cmd.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename...ARGS>
|
|
||||||
static void send(CD_IO::Command::Info cmd, ARGS...args) {
|
|
||||||
send(T::CommandFifo, T::ParameterFifo, cmd, args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename...ARGS>
|
|
||||||
static void send_wait(CD_IO::CommandFifo_t& cmd_fifo, CD_IO::ParameterFifo_t& parameter_fifo, CD_IO::Command::Info cmd, ARGS...args) {
|
|
||||||
send(cmd_fifo, parameter_fifo, cmd, args...);
|
|
||||||
wait_until(cmd.complete_irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename...ARGS>
|
|
||||||
static void send_wait(CD_IO::Command::Info cmd, ARGS...args) {
|
|
||||||
send_wait(T::CommandFifo, T::ParameterFifo, cmd, args...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
State read_file(FileInfo file_info, const SectorBufferAllocator& buffer_allocator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //!__JABYENGINE_CD_INTERNAL_HPP__
|
|
|
@ -1,120 +0,0 @@
|
||||||
#ifndef __JABYENGINE_GPU_INTERNAL_HPP__
|
|
||||||
#define __JABYENGINE_GPU_INTERNAL_HPP__
|
|
||||||
#include <PSX/GPU/gpu.hpp>
|
|
||||||
#include <PSX/System/IOPorts/dma_io.hpp>
|
|
||||||
#include <PSX/System/IOPorts/gpu_io.hpp>
|
|
||||||
|
|
||||||
namespace JabyEngine {
|
|
||||||
namespace GPU {
|
|
||||||
namespace internal {
|
|
||||||
struct Screen {
|
|
||||||
struct Mode {
|
|
||||||
enum struct TVEncoding {
|
|
||||||
NTSC = 0,
|
|
||||||
PAL = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr auto HorizontalResolution368 = Bit<uint32_t>(6);
|
|
||||||
static constexpr auto VerticalInterlace = Bit<uint32_t>(5);
|
|
||||||
static constexpr auto DisplayAreaColorDepth = BitRange<GPU_IO::DisplayAreaColorDepth>::from_to(4, 4);
|
|
||||||
static constexpr auto VideoMode = BitRange<TVEncoding>::from_to(3, 3);
|
|
||||||
static constexpr auto VerticalResolution = BitRange<GPU_IO::VerticalResolution>::from_to(2, 2);
|
|
||||||
static constexpr auto HorizontalResolution = BitRange<GPU_IO::HorizontalResolution>::from_to(0, 1);
|
|
||||||
|
|
||||||
static constexpr uint32_t PAL() {
|
|
||||||
return ComplexBitMap<uint32_t>::with(
|
|
||||||
Mode::HorizontalResolution.with(GPU_IO::HorizontalResolution::$320),
|
|
||||||
Mode::VerticalResolution.with(GPU_IO::VerticalResolution::$240),
|
|
||||||
Mode::VideoMode.with(TVEncoding::PAL),
|
|
||||||
Mode::DisplayAreaColorDepth.with(GPU_IO::DisplayAreaColorDepth::$15bit)
|
|
||||||
).raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr uint32_t NTSC() {
|
|
||||||
return ComplexBitMap<uint32_t>::with(
|
|
||||||
Mode::HorizontalResolution.with(GPU_IO::HorizontalResolution::$320),
|
|
||||||
Mode::VerticalResolution.with(GPU_IO::VerticalResolution::$240),
|
|
||||||
Mode::VideoMode.with(TVEncoding::NTSC),
|
|
||||||
Mode::DisplayAreaColorDepth.with(GPU_IO::DisplayAreaColorDepth::$15bit)
|
|
||||||
).raw;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void configurate() {
|
|
||||||
static constexpr uint16_t FirstVisiblePixelH = 0x260;
|
|
||||||
|
|
||||||
#ifdef JABYENGINE_PAL
|
|
||||||
static constexpr uint16_t FirstVisiblePixelV = 0xA3;
|
|
||||||
|
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::DisplayMode(Mode::PAL()));
|
|
||||||
GPU::Screen::set_offset(0, 0);
|
|
||||||
#else
|
|
||||||
static constexpr uint16_t FirstVisiblePixelV = 0x88;
|
|
||||||
|
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::DisplayMode(Mode::NTSC()));
|
|
||||||
GPU::Screen::set_offset(0, 5); //< Random values
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exchange_buffer_and_display();
|
|
||||||
};
|
|
||||||
|
|
||||||
static void set_draw_area(uint16_t x, uint16_t y) {
|
|
||||||
GPU_IO::GP0.write(GPU_IO::Command::GP0::DrawAreaTopLeft(x, y));
|
|
||||||
GPU_IO::GP0.write(GPU_IO::Command::GP0::DrawAreaBottomRight((x + Display::Width), (y + Display::Height)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void quick_fill_fast(const Color24& color, const PositionU16& pos, const SizeU16& size) {
|
|
||||||
GPU_IO::GP0.write(GPU_IO::Command::GP0::QuickFill(color));
|
|
||||||
GPU_IO::GP0.write(GPU_IO::Command::GP0::TopLeftPosition(pos.x, pos.y));
|
|
||||||
GPU_IO::GP0.write(GPU_IO::Command::GP0::WidthHeight(size.width, size.height));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reset_cmd_buffer() {
|
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::ResetCMDBufer());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wait_ready_for_CMD() {
|
|
||||||
while(!GPU_IO::GPUSTAT.read().is(GPU_IO::GPUStatusRegister::GP0ReadyForCMD));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace DMA {
|
|
||||||
static void wait() {
|
|
||||||
while(::JabyEngine::DMA_IO::GPU.channel_ctrl.read().is(::JabyEngine::DMA_IO::CHCHR::Busy));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void end() {
|
|
||||||
reset_cmd_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Receive {
|
|
||||||
static void prepare()
|
|
||||||
{
|
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::DMADirection(GPU_IO::DMADirection::CPU2GPU));
|
|
||||||
reset_cmd_buffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_src(uintptr_t adr) {
|
|
||||||
DMA_IO::GPU.adr.write(DMA_IO::MADR::MemoryAdr.with(static_cast<uint32_t>(adr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_dst(const PositionU16& position, const SizeU16& size) {
|
|
||||||
wait_ready_for_CMD();
|
|
||||||
GPU_IO::GP0.write(GPU_IO::Command::GP0::CPU2VRAM_Blitting());
|
|
||||||
GPU_IO::GP0.write(GPU_IO::Command::GP0::TopLeftPosition(position.x, position.y));
|
|
||||||
GPU_IO::GP0.write(GPU_IO::Command::GP0::WidthHeight(size.width, size.height));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) {
|
|
||||||
typedef DMA_IO::BCR::SyncMode1 SyncMode1;
|
|
||||||
|
|
||||||
DMA_IO::GPU.block_ctrl.write(DMA_IO::BCR{SyncMode1::with(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount))});
|
|
||||||
DMA_IO::GPU.channel_ctrl.write(DMA_IO::CHCHR::StartGPUReceive());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //!__JABYENGINE_GPU_INTERNAL_HPP__
|
|
|
@ -3,12 +3,7 @@
|
||||||
#include <PSX/jabyengine.hpp>
|
#include <PSX/jabyengine.hpp>
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
//boot namespace?
|
|
||||||
namespace boot {
|
namespace boot {
|
||||||
namespace BootFile {
|
|
||||||
JabyEngine::NextRoutine setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace CD {
|
namespace CD {
|
||||||
void setup();
|
void setup();
|
||||||
}
|
}
|
||||||
|
@ -23,13 +18,11 @@ namespace JabyEngine {
|
||||||
void setup();
|
void setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Start {
|
|
||||||
JabyEngine::NextRoutine setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Timer {
|
namespace Timer {
|
||||||
void setup();
|
void setup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __no_return run();
|
||||||
}
|
}
|
||||||
#endif //!BOOT_LOADER_HPP
|
#endif //!BOOT_LOADER_HPP
|
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef __JABYENGINE_CD_INTERNAL_HPP__
|
||||||
|
#define __JABYENGINE_CD_INTERNAL_HPP__
|
||||||
|
#include "cd_types.hpp"
|
||||||
|
|
||||||
|
namespace JabyEngine {
|
||||||
|
namespace CD {
|
||||||
|
namespace internal {
|
||||||
|
extern State current_state;
|
||||||
|
extern CD_IO::Interrupt::Type last_interrupt;
|
||||||
|
extern uint8_t cmd_interrupt_bit;
|
||||||
|
|
||||||
|
struct Command {
|
||||||
|
static void wait_completed() {
|
||||||
|
while(const_cast<volatile uint8_t&>(cmd_interrupt_bit) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ARGS>
|
||||||
|
static void send(CD_IO::CommandFifo_v& cmd_fifo, CD_IO::ParameterFifo_v& parameter_fifo, CD_IO::Command::Desc cmd, ARGS...args) {
|
||||||
|
while(CD_IO::IndexStatus.is_set(CD_IO::IndexStatus_t::IsTransmissionBusy));
|
||||||
|
|
||||||
|
((parameter_fifo = args),...);
|
||||||
|
cmd_fifo = cmd.id;
|
||||||
|
cmd_interrupt_bit = bit::set(0, cmd.complete_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename...ARGS>
|
||||||
|
static void send(CD_IO::Command::Desc cmd, ARGS...args) {
|
||||||
|
send(T::CommandFifo, T::ParameterFifo, cmd, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...ARGS>
|
||||||
|
static void send_wait(CD_IO::CommandFifo_v& cmd_fifo, CD_IO::ParameterFifo_v& parameter_fifo, CD_IO::Command::Desc cmd, ARGS...args) {
|
||||||
|
send(cmd_fifo, parameter_fifo, cmd, args...);
|
||||||
|
wait_completed();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename...ARGS>
|
||||||
|
static void send_wait(CD_IO::Command::Desc cmd, ARGS...args) {
|
||||||
|
send_wait(T::CommandFifo, T::ParameterFifo, cmd, args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static State read_current_state() {
|
||||||
|
return const_cast<volatile State&>(current_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator);
|
||||||
|
void continue_reading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //!__JABYENGINE_CD_INTERNAL_HPP__
|
|
@ -2,6 +2,7 @@
|
||||||
#define __JABYENGINE_INTERNAL_CD_TYPES_HPP__
|
#define __JABYENGINE_INTERNAL_CD_TYPES_HPP__
|
||||||
#include <PSX/AutoLBA/auto_lba.hpp>
|
#include <PSX/AutoLBA/auto_lba.hpp>
|
||||||
#include <PSX/Auxiliary/math_helper.hpp>
|
#include <PSX/Auxiliary/math_helper.hpp>
|
||||||
|
#include <PSX/System/IOPorts/cd_io.hpp>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
|
@ -16,30 +17,9 @@ namespace JabyEngine {
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DataSector {
|
|
||||||
static constexpr size_t SizeBytes = 2048;
|
|
||||||
static constexpr size_t SizeWords = (SizeBytes/sizeof(uint32_t));
|
|
||||||
|
|
||||||
uint32_t data[SizeWords];
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static constexpr T words_to_sectors(T size) {
|
|
||||||
return (size + static_cast<T>(DataSector::SizeWords - 1))/static_cast<T>(DataSector::SizeWords);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileInfo {
|
|
||||||
uint16_t lba;
|
|
||||||
uint16_t sectors;
|
|
||||||
|
|
||||||
static constexpr FileInfo from(const AutoLBAEntry& entry) {
|
|
||||||
return FileInfo{entry.lba, DataSector::words_to_sectors(entry.size_words)};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SectorBufferAllocator {
|
class SectorBufferAllocator {
|
||||||
private:
|
private:
|
||||||
typedef DataSector* (*AllocatorFunction)(void* ctx);
|
typedef CD_IO::DataSector* (*AllocatorFunction)(void* ctx);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* ctx = nullptr;
|
void* ctx = nullptr;
|
||||||
|
@ -54,6 +34,14 @@ namespace JabyEngine {
|
||||||
static constexpr SectorBufferAllocator create(void* obj, AllocatorFunction function) {
|
static constexpr SectorBufferAllocator create(void* obj, AllocatorFunction function) {
|
||||||
return SectorBufferAllocator(obj, function);
|
return SectorBufferAllocator(obj, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr SectorBufferAllocator invalid() {
|
||||||
|
return SectorBufferAllocator(nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CD_IO::DataSector* allocate_sector() const {
|
||||||
|
return this->allocate(this->ctx);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CDTimeStamp {
|
struct CDTimeStamp {
|
||||||
|
@ -64,17 +52,13 @@ namespace JabyEngine {
|
||||||
uint8_t sec;
|
uint8_t sec;
|
||||||
uint8_t sector;
|
uint8_t sector;
|
||||||
|
|
||||||
static constexpr CDTimeStamp from(uint16_t lba) {
|
static constexpr CDTimeStamp from(uint32_t lba) {
|
||||||
const auto [min, new_lba] = div_and_mod(lba, static_cast<uint16_t>(MaxSector*MaxSeconds));
|
const auto [min, new_lba] = div_and_mod(lba, MaxSector*MaxSeconds);
|
||||||
const auto [sec, sectors] = div_and_mod(new_lba, static_cast<uint16_t>(MaxSector));
|
const auto [sec, sectors] = div_and_mod(new_lba, MaxSector);
|
||||||
|
|
||||||
return CDTimeStamp{static_cast<uint8_t>(min), static_cast<uint8_t>(sec), static_cast<uint8_t>(sectors)};
|
return CDTimeStamp{static_cast<uint8_t>(min), static_cast<uint8_t>(sec), static_cast<uint8_t>(sectors)};
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr CDTimeStamp from(const FileInfo& file_info) {
|
|
||||||
return CDTimeStamp::from(file_info.lba);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr uint8_t get_min_cd() const {
|
constexpr uint8_t get_min_cd() const {
|
||||||
return to_bcd(this->min);
|
return to_bcd(this->min);
|
||||||
}
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
#ifndef __JABYENGINE_GPU_INTERNAL_HPP__
|
||||||
|
#define __JABYENGINE_GPU_INTERNAL_HPP__
|
||||||
|
#include <PSX/GPU/gpu.hpp>
|
||||||
|
#include <PSX/System/IOPorts/dma_io.hpp>
|
||||||
|
#include <PSX/System/IOPorts/gpu_io.hpp>
|
||||||
|
|
||||||
|
namespace JabyEngine {
|
||||||
|
namespace GPU {
|
||||||
|
namespace internal {
|
||||||
|
struct Screen {
|
||||||
|
static void configurate() {
|
||||||
|
static constexpr uint16_t FirstVisiblePixelH = 0x260;
|
||||||
|
|
||||||
|
#ifdef JABYENGINE_PAL
|
||||||
|
static constexpr uint16_t FirstVisiblePixelV = 0xA3;
|
||||||
|
|
||||||
|
GPU_IO::GP1 = GPU_IO::Command::DisplayMode(GPU_IO::DisplayMode_t::PAL());
|
||||||
|
GPU::Screen::set_offset(0, 0);
|
||||||
|
#else
|
||||||
|
static constexpr uint16_t FirstVisiblePixelV = 0x88;
|
||||||
|
|
||||||
|
GPU_IO::GP1 = GPU_IO::Command::DisplayMode(GPU_IO::DisplayMode_t::NTSC());
|
||||||
|
GPU::Screen::set_offset(0, 5); //< Random values
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exchange_buffer_and_display();
|
||||||
|
};
|
||||||
|
|
||||||
|
static void set_draw_area(uint16_t x, uint16_t y) {
|
||||||
|
GPU_IO::GP0 = GPU_IO::Command::DrawAreaTopLeft(x, y);
|
||||||
|
GPU_IO::GP0 = GPU_IO::Command::DrawAreaBottomRight((x + Display::Width), (y + Display::Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void quick_fill_fast(const Color24& color, const PositionU16& pos, const SizeU16& size) {
|
||||||
|
GPU_IO::GP0 = GPU_IO::Command::QuickFill(color);
|
||||||
|
GPU_IO::GP0 = GPU_IO::Command::TopLeftPosition(pos.x, pos.y);
|
||||||
|
GPU_IO::GP0 = GPU_IO::Command::WidthHeight(size.width, size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reset_cmd_buffer() {
|
||||||
|
GPU_IO::GP1 = GPU_IO::Command::ResetCMDBufer();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wait_ready_for_CMD() {
|
||||||
|
while(!GPU_IO::GPUSTAT.is_set(GPU_IO::GPUSTAT_t::GP0ReadyForCMD));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace DMA {
|
||||||
|
static void wait() {
|
||||||
|
::JabyEngine::DMA_IO::GPU.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end() {
|
||||||
|
reset_cmd_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Receive {
|
||||||
|
static void prepare() {
|
||||||
|
GPU_IO::GP1 = GPU_IO::Command::DMADirection(GPU_IO::DMADirection::CPU2GPU);
|
||||||
|
reset_cmd_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_src(uintptr_t adr) {
|
||||||
|
DMA_IO::GPU.set_adr(adr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_dst(const PositionU16& position, const SizeU16& size) {
|
||||||
|
wait_ready_for_CMD();
|
||||||
|
GPU_IO::GP0 = GPU_IO::Command::CPU2VRAM_Blitting();
|
||||||
|
GPU_IO::GP0 = GPU_IO::Command::TopLeftPosition(position.x, position.y);
|
||||||
|
GPU_IO::GP0 = GPU_IO::Command::WidthHeight(size.width, size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) {
|
||||||
|
typedef DMA_IO::BCR_t::SyncMode1 SyncMode1;
|
||||||
|
|
||||||
|
DMA_IO::GPU.block_ctrl = DMA_IO::BCR_t::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount));
|
||||||
|
DMA_IO::GPU.channel_ctrl = DMA_IO::CHCHR_t::StartGPUReceive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //!__JABYENGINE_GPU_INTERNAL_HPP__
|
|
@ -24,11 +24,11 @@ namespace JabyEngine {
|
||||||
|
|
||||||
void LZ4Decompressor :: setup(uint8_t* dst_adr) {
|
void LZ4Decompressor :: setup(uint8_t* dst_adr) {
|
||||||
this->dst_adr = dst_adr;
|
this->dst_adr = dst_adr;
|
||||||
LZ4Decompressor::reset();
|
this->state.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LZ4Decompressor :: reset() {
|
void LZ4Decompressor :: disable() {
|
||||||
this->state = State();
|
this->state.disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
LZ4Decompressor::Result LZ4Decompressor :: process(ArrayRange<const uint8_t> data, bool is_last) {
|
LZ4Decompressor::Result LZ4Decompressor :: process(ArrayRange<const uint8_t> data, bool is_last) {
|
||||||
|
@ -36,6 +36,9 @@ namespace JabyEngine {
|
||||||
|
|
||||||
while(data) {
|
while(data) {
|
||||||
switch(this->state.step) {
|
switch(this->state.step) {
|
||||||
|
case State::Step::Disabled:
|
||||||
|
return Result::new_done(data.size);
|
||||||
|
|
||||||
case State::Step::ReadToken: {
|
case State::Step::ReadToken: {
|
||||||
const auto token = data.pop();
|
const auto token = data.pop();
|
||||||
|
|
||||||
|
@ -67,9 +70,10 @@ namespace JabyEngine {
|
||||||
memcpy(this->dst_adr, data, bytes_copy);
|
memcpy(this->dst_adr, data, bytes_copy);
|
||||||
|
|
||||||
this->state.literal_length -= bytes_copy;
|
this->state.literal_length -= bytes_copy;
|
||||||
|
bytes_ready += bytes_copy;
|
||||||
|
|
||||||
if(this->state.literal_length == 0) {
|
if(this->state.literal_length == 0) {
|
||||||
this->state.step = State::Step::ObtainMatchOffset;
|
this->state.step = State::Step::ObtainMatchOffset;
|
||||||
bytes_ready += bytes_copy;
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
#include "../../../include/BootLoader/boot_loader.hpp"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <PSX/File/Processor/cd_file_processor.hpp>
|
|
||||||
|
|
||||||
extern JabyEngine::NextRoutine main();
|
|
||||||
|
|
||||||
namespace JabyEngine {
|
|
||||||
namespace boot {
|
|
||||||
namespace BootFile {
|
|
||||||
JabyEngine::NextRoutine setup() {
|
|
||||||
printf("Running main!\n");
|
|
||||||
return JabyEngine::NextRoutine::from(main);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
#include "../../../include/BootLoader/boot_loader.hpp"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
namespace JabyEngine {
|
|
||||||
namespace boot {
|
|
||||||
namespace BootFile {
|
|
||||||
JabyEngine::NextRoutine setup() {
|
|
||||||
printf("Overlay boot not implemented!\n");
|
|
||||||
return JabyEngine::NextRoutine::null();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "../../include/BootLoader/boot_loader.hpp"
|
#include "../../internal-include/BootLoader/boot_loader.hpp"
|
||||||
#include "../../include/CD/cd_internal.hpp"
|
#include "../../internal-include/CD/cd_internal.hpp"
|
||||||
#include <PSX/System/IOPorts/interrupt_io.hpp>
|
#include <PSX/System/IOPorts/interrupt_io.hpp>
|
||||||
#include <PSX/System/IOPorts/memory_io.hpp>
|
#include <PSX/System/IOPorts/memory_io.hpp>
|
||||||
#include <PSX/System/syscalls.h>
|
#include <PSX/System/syscalls.h>
|
||||||
|
@ -16,20 +16,19 @@ namespace JabyEngine {
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
__syscall_EnterCriticalSection();
|
__syscall_EnterCriticalSection();
|
||||||
Memory_IO::COM_DELAY.write(Memory_IO::COM_DELAY::SetupValue);
|
Memory_IO::COM_DELAY.setup();
|
||||||
Memory_IO::CD_DELAY.write(Memory_IO::CD_DELAY::SetupValue);
|
Memory_IO::CD_DELAY.setup();
|
||||||
|
|
||||||
__syscall_SysEnqIntRP(CdromIoIrq, &::JabyEngine::CD::internal::callback);
|
__syscall_SysEnqIntRP(CdromIoIrq, &::JabyEngine::CD::internal::callback);
|
||||||
|
|
||||||
CD_IO::PortIndex1::change_to();
|
CD_IO::PortIndex1::change_to();
|
||||||
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlagRegister);
|
CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag);
|
||||||
CD_IO::Interrupt::enable(CD_IO::PortIndex1::InterruptEnableRegister);
|
CD_IO::Interrupt::enable(CD_IO::PortIndex1::InterruptEnable);
|
||||||
|
|
||||||
Interrupt::ack_irq(Interrupt::CDROM);
|
|
||||||
Interrupt::enable_irq(Interrupt::CDROM);
|
Interrupt::enable_irq(Interrupt::CDROM);
|
||||||
|
Interrupt::ack_irq(Interrupt::CDROM);
|
||||||
__syscall_ExitCriticalSection();
|
__syscall_ExitCriticalSection();
|
||||||
|
|
||||||
|
|
||||||
CD_IO::PortIndex0::change_to();
|
CD_IO::PortIndex0::change_to();
|
||||||
|
|
||||||
Command::send_wait(CD_IO::PortIndex0::CommandFifo, CD_IO::PortIndex0::ParameterFifo, CD_IO::Command::GetStat);
|
Command::send_wait(CD_IO::PortIndex0::CommandFifo, CD_IO::PortIndex0::ParameterFifo, CD_IO::Command::GetStat);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "../../include/GPU/gpu_internal.hpp"
|
#include "../../internal-include/GPU/gpu_internal.hpp"
|
||||||
#include <PSX/File/Processor/file_processor.hpp>
|
#include <PSX/File/Processor/file_processor.hpp>
|
||||||
#include <PSX/Auxiliary/lz4_decompressor.hpp>
|
#include <PSX/Auxiliary/lz4_decompressor.hpp>
|
||||||
#include <PSX/GPU/gpu.hpp>
|
#include <PSX/GPU/gpu.hpp>
|
||||||
|
@ -43,13 +43,13 @@ namespace JabyEngine {
|
||||||
|
|
||||||
// Upload SplashScreen picture
|
// Upload SplashScreen picture
|
||||||
auto state = FileProcessor::create(&__boot_loader_end, SimpleTIM(32, 0, 0, 0));
|
auto state = FileProcessor::create(&__boot_loader_end, SimpleTIM(32, 0, 0, 0));
|
||||||
while(state.process((bytes_ready/sizeof(uint32_t))) == Progress::InProgress);
|
state.process(bytes_ready);
|
||||||
|
|
||||||
Display::enable();
|
Display::enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::Reset());
|
GPU_IO::GP1 = GPU_IO::Command::Reset();
|
||||||
internal::Screen::configurate();
|
internal::Screen::configurate();
|
||||||
internal::Screen::exchange_buffer_and_display();
|
internal::Screen::exchange_buffer_and_display();
|
||||||
|
|
||||||
|
|
|
@ -6,65 +6,66 @@ namespace JabyEngine {
|
||||||
namespace boot {
|
namespace boot {
|
||||||
namespace SPU {
|
namespace SPU {
|
||||||
using namespace JabyEngine;
|
using namespace JabyEngine;
|
||||||
|
using namespace SPU_IO;
|
||||||
|
|
||||||
static void clear_main_volume() {
|
static void clear_main_volume() {
|
||||||
static constexpr auto StartVol = SPU_IO::SweepVolume::with(SPU_IO::SweepVolume::VolumeEnable, SPU_IO::SweepVolume::Volume.with(I16_MAX >> 2));
|
static constexpr auto StartVol = SweepVolume_t::from(SweepVolume_t::VolumeEnable, SweepVolume_t::Volume.with(static_cast<int16_t>(I16_MAX >> 2)));
|
||||||
|
|
||||||
SPU_IO::MainVolume::Left.write({StartVol});
|
MainVolume::Left = StartVol;
|
||||||
SPU_IO::MainVolume::Right.write({StartVol});
|
MainVolume::Right = StartVol;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_cd_and_ext_audio_volume() {
|
static void clear_cd_and_ext_audio_volume() {
|
||||||
SPU_IO::CDVolume::Left.write(0);
|
CDVolume::Left = 0;
|
||||||
SPU_IO::CDVolume::Right.write(0);
|
CDVolume::Right = 0;
|
||||||
|
|
||||||
SPU_IO::ExternalAudioInputVolume::Left.write(0);
|
ExternalAudioInputVolume::Left = 0;
|
||||||
SPU_IO::ExternalAudioInputVolume::Right.write(0);
|
ExternalAudioInputVolume::Right = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_control_register() {
|
static void clear_control_register() {
|
||||||
SPU_IO::Control.write(SPU_IO::ControlRegister());
|
ControlRegister = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_voice() {
|
static void clear_voice() {
|
||||||
for(auto& voice : SPU_IO::Voice) {
|
for(auto& voice : SPU_IO::Voice) {
|
||||||
voice.volumeLeft.write(SPU_IO::SweepVolume());
|
voice.volumeLeft = SweepVolume_t();
|
||||||
voice.volumeRight.write(SPU_IO::SweepVolume());
|
voice.volumeRight = SweepVolume_t();
|
||||||
voice.sampleRate.write(SPU_IO::SampleRate());
|
voice.sampleRate = SampleRate_t();
|
||||||
voice.ad.write(SPU_IO::AD());
|
voice.ad = AD_t();
|
||||||
voice.sr.write(SPU_IO::SR());
|
voice.sr = SR_t();
|
||||||
voice.currentVolume.write(SPU_IO::SimpleVolume(0));
|
voice.currentVolume = 0;
|
||||||
|
|
||||||
voice.adr.write(0x200);
|
voice.adr = 0x200;
|
||||||
voice.repeatAdr.write(0x200);
|
voice.repeatAdr = 0x200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_pmon() {
|
static void clear_pmon() {
|
||||||
SPU_IO::PMON.write(SPU_IO::PitchModFlags());
|
SPU_IO::PMON = PMON_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_noise_and_echo() {
|
static void clear_noise_and_echo() {
|
||||||
SPU_IO::NON.write(SPU_IO::NoiseGenerator());
|
SPU_IO::NON = NON_t();
|
||||||
SPU_IO::EON.write(SPU_IO::EchoOn());
|
SPU_IO::EON = EON_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_reverb() {
|
static void clear_reverb() {
|
||||||
SPU_IO::Reverb::Volume::Left.write(0);
|
Reverb::Volume::Left = 0;
|
||||||
SPU_IO::Reverb::Volume::Right.write(0);
|
Reverb::Volume::Right = 0;
|
||||||
SPU_IO::Reverb::WorkAreaAdr.write(0);
|
Reverb::WorkAreaAdr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_control_register() {
|
static void setup_control_register() {
|
||||||
static constexpr auto SetupValue = SPU_IO::ControlRegister::with(SPU_IO::ControlRegister::Enable, SPU_IO::ControlRegister::Unmute, SPU_IO::ControlRegister::CDAudioEnable);
|
static constexpr auto SetupValue = ControlRegister_t::from(ControlRegister_t::Enable, ControlRegister_t::Unmute, ControlRegister_t::CDAudioEnable);
|
||||||
|
|
||||||
SPU_IO::Control.write({SetupValue});
|
SPU_IO::ControlRegister = SetupValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_data_transfer_control() {
|
static void setup_data_transfer_control() {
|
||||||
static constexpr uint16_t RequiredValue = (2 << 1);
|
static constexpr uint16_t RequiredValue = (2 << 1);
|
||||||
|
|
||||||
SPU_IO::DataTransferControl.write(RequiredValue);
|
DataTransferControl = RequiredValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wait_voices() {
|
static void wait_voices() {
|
||||||
|
@ -72,7 +73,7 @@ namespace JabyEngine {
|
||||||
|
|
||||||
try_again:
|
try_again:
|
||||||
for(const auto& voice : SPU_IO::Voice) {
|
for(const auto& voice : SPU_IO::Voice) {
|
||||||
if(voice.currentVolume.read() > Treshhold) {
|
if(voice.currentVolume > Treshhold) {
|
||||||
goto try_again;
|
goto try_again;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
#include "BootLoader/boot_loader.hpp"
|
#include "../../internal-include/BootLoader/boot_loader.hpp"
|
||||||
#include <PSX/System/IOPorts/dMa_io.hpp>
|
#include <PSX/System/IOPorts/dMa_io.hpp>
|
||||||
|
|
||||||
|
// 2x For setup timing
|
||||||
#include <PSX/Timer/high_res_timer.hpp>
|
#include <PSX/Timer/high_res_timer.hpp>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace boot {
|
namespace boot {
|
||||||
namespace Start {
|
namespace Start {
|
||||||
|
//This should become part of the bootloader later
|
||||||
static void enable_DMA() {
|
static void enable_DMA() {
|
||||||
DMA_IO::DPCR.write(DMA_IO::DMAControlRegister{DMA_IO::DPCR.read() | DMA_IO::DMAControlRegister::SPUEnable | DMA_IO::DMAControlRegister::GPUEnable});
|
DMA_IO::DPCR = DMA_IO::DPCR_t(DMA_IO::DPCR).set(DMA_IO::DPCR_t::SPUEnable).set(DMA_IO::DPCR_t::GPUEnable).set(DMA_IO::DPCR_t::CDROMEnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
JabyEngine::NextRoutine setup() {
|
static void setup() {
|
||||||
enable_DMA();
|
enable_DMA();
|
||||||
|
|
||||||
SPU::stop_voices();
|
SPU::stop_voices();
|
||||||
|
@ -29,8 +31,15 @@ namespace JabyEngine {
|
||||||
//Pause??
|
//Pause??
|
||||||
|
|
||||||
SPU::setup();
|
SPU::setup();
|
||||||
return BootFile::setup();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void start() {
|
||||||
|
printf("Starting Planschbecken\n");
|
||||||
|
boot::Start::setup();
|
||||||
|
|
||||||
|
printf("Running main...\n");
|
||||||
|
run();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,7 @@
|
||||||
void setup() {
|
void setup() {
|
||||||
using namespace Timer_IO;
|
using namespace Timer_IO;
|
||||||
|
|
||||||
static constexpr auto Mode = CounterMode::with(CounterMode::FreeRun, Counter2::SyncMode::Freerun, CounterMode::ResetAfterTarget, CounterMode::IRQAtTarget, CounterMode::IRQEveryTime, CounterMode::IRQPulse, Counter2::Source::System_Clock_Div_8);
|
static constexpr auto Mode = CounterMode_t::from(CounterMode_t::FreeRun, Counter2_v::SyncMode::FreeRun, CounterMode_t::ResetAfterTarget, CounterMode_t::IRQAtTarget, CounterMode_t::IRQEveryTime, CounterMode_t::IRQPulse, Counter2_v::Source::System_Clock_Div_8);
|
||||||
|
|
||||||
Interrupt::disable_irq(Interrupt::Timer2);
|
Interrupt::disable_irq(Interrupt::Timer2);
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@
|
||||||
__syscall_SysEnqIntRP(Timer2Irq, &IRQCallback);
|
__syscall_SysEnqIntRP(Timer2Irq, &IRQCallback);
|
||||||
__syscall_ExitCriticalSection();
|
__syscall_ExitCriticalSection();
|
||||||
|
|
||||||
Counter2.target.write(CounterTarget::CounterTargetValue.with(HighResTime::TicksFor10ms));
|
Counter2.set_target_value(HighResTime::TicksFor10ms);
|
||||||
Counter2.mode.write({Mode});
|
Counter2.set_mode(Mode);
|
||||||
|
|
||||||
Interrupt::enable_irq(Interrupt::Timer2);
|
Interrupt::enable_irq(Interrupt::Timer2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,47 +1,109 @@
|
||||||
#include "../../include/CD/cd_internal.hpp"
|
#include "../../internal-include/CD/cd_internal.hpp"
|
||||||
|
#include <PSX/System/IOPorts/dma_io.hpp>
|
||||||
#include <PSX/System/IOPorts/interrupt_io.hpp>
|
#include <PSX/System/IOPorts/interrupt_io.hpp>
|
||||||
#include <PSX/System/syscalls.h>
|
#include <PSX/System/syscalls.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace CD {
|
namespace CD {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
struct Mode : public ComplexBitMap<uint8_t> {
|
static constexpr auto DataSectorMode = CD_IO::Mode_t::from(CD_IO::Mode_t::DoubleSpeed, CD_IO::Mode_t::DataSector);
|
||||||
static constexpr auto DoubleSpeed = Bit<uint8_t>(7);
|
|
||||||
static constexpr auto SingleSpeed = !DoubleSpeed;
|
static InterruptVerifierResult interrupt_verifier();
|
||||||
static constexpr auto XADPCM = Bit<uint8_t>(6);
|
static void interrupt_handler(uint32_t);
|
||||||
static constexpr auto WholeSector = Bit<uint8_t>(5);
|
|
||||||
static constexpr auto DataSector = !WholeSector;
|
static SectorBufferAllocator sector_allocator;
|
||||||
static constexpr auto UseXAFilter = Bit<uint8_t>(3);
|
static uint32_t cur_lba;
|
||||||
static constexpr auto AudioPlayIRQ = Bit<uint8_t>(2);
|
static uint32_t dst_lba;
|
||||||
static constexpr auto AutoPauseTrack = Bit<uint8_t>(1);
|
|
||||||
static constexpr auto CDDA = Bit<uint8_t>(0);
|
CD_IO::Interrupt::Type last_interrupt = CD_IO::Interrupt::Type::None;
|
||||||
|
uint8_t cmd_interrupt_bit = 0;
|
||||||
|
State current_state = State::Free;
|
||||||
|
InterrupCallback callback = {
|
||||||
|
.next = nullptr,
|
||||||
|
.handler_function = reinterpret_cast<InterruptHandler>(interrupt_handler),
|
||||||
|
.verifier_function = interrupt_verifier
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr auto DataSectorMode = Mode::with(Mode::DoubleSpeed, Mode::DataSector);
|
static void pause_cd() {
|
||||||
|
CD_IO::PortIndex0::change_to();
|
||||||
static SectorBufferAllocator sector_allocator;
|
Command::send<CD_IO::PortIndex0>(CD_IO::Command::Pause);
|
||||||
static uint16_t sectors_left;
|
}
|
||||||
|
|
||||||
|
// Requires Index0
|
||||||
|
static void read_cd(uint32_t lba) {
|
||||||
|
const auto loc = CDTimeStamp::from(lba);
|
||||||
|
|
||||||
|
Command::send_wait<CD_IO::PortIndex0>(CD_IO::Command::SetLoc, loc.get_min_cd(), loc.get_sec_cd(), loc.get_sector_cd());
|
||||||
|
Command::send<CD_IO::PortIndex0>(CD_IO::Command::ReadN);
|
||||||
|
current_state = State::Reading;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_sector_dma(CD_IO::DataSector& sector) {
|
||||||
|
static const auto WaitSectorReady = []() {
|
||||||
|
while(!CD_IO::IndexStatus.is_set(CD_IO::IndexStatus_t::HasDataFifoData));
|
||||||
|
};
|
||||||
|
|
||||||
|
static const auto ReadSector = [](uint32_t* dst) {
|
||||||
|
DMA_IO::CDROM.set_adr(reinterpret_cast<uintptr_t>(dst));
|
||||||
|
DMA_IO::CDROM.block_ctrl = DMA_IO::BCR_t::SyncMode0::for_cd();
|
||||||
|
DMA_IO::CDROM.channel_ctrl = DMA_IO::CHCHR_t::StartCDROM();
|
||||||
|
|
||||||
|
DMA_IO::CDROM.wait();
|
||||||
|
|
||||||
|
CD_IO::PortIndex0::Request.reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
WaitSectorReady();
|
||||||
|
ReadSector(sector.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void read_sector_to(CD_IO::DataSector& sector) {
|
||||||
|
CD_IO::PortIndex0::change_to();
|
||||||
|
CD_IO::PortIndex0::Request.want_data();
|
||||||
|
|
||||||
|
// We only support DMA rn
|
||||||
|
read_sector_dma(sector);
|
||||||
|
|
||||||
|
// Do we ever want to support reading via IO Port?
|
||||||
|
// Doesn't seem to important when we can use DMA
|
||||||
|
}
|
||||||
|
|
||||||
static InterruptVerifierResult interrupt_verifier() {
|
static InterruptVerifierResult interrupt_verifier() {
|
||||||
if(Interrupt::is_irq(Interrupt::CDROM)) {
|
if(Interrupt::is_irq(Interrupt::CDROM)) {
|
||||||
const uint8_t old_idx = (CD_IO::IndexStatus.read() & 0x3);
|
const uint8_t old_status = CD_IO::IndexStatus;
|
||||||
|
|
||||||
CD_IO::PortIndex1::change_to();
|
CD_IO::PortIndex1::change_to();
|
||||||
const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlagRegister);
|
const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag);
|
||||||
last_interrupt.write(cur_irq);
|
last_interrupt = cur_irq;
|
||||||
CD_IO::Interrupt::ack(CD_IO::PortIndex1::InterruptFlagRegister);
|
CD_IO::Interrupt::ack(CD_IO::PortIndex1::InterruptFlag);
|
||||||
|
|
||||||
|
cmd_interrupt_bit = bit::clear(cmd_interrupt_bit, cur_irq);
|
||||||
if(cur_irq == CD_IO::Interrupt::DataReady) {
|
if(cur_irq == CD_IO::Interrupt::DataReady) {
|
||||||
sectors_left--;
|
// Obtain sector content here
|
||||||
if(sectors_left == 0) {
|
auto* sector = sector_allocator.allocate_sector();
|
||||||
CD_IO::PortIndex0::change_to();
|
if(sector) {
|
||||||
Command::send<CD_IO::PortIndex0>(CD_IO::Command::Pause);
|
//Now obtain sector
|
||||||
|
read_sector_to(*sector);
|
||||||
|
|
||||||
|
cur_lba++;
|
||||||
|
if(cur_lba == dst_lba) {
|
||||||
|
current_state = State::Done;
|
||||||
|
pause_cd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
current_state = State::BufferFull;
|
||||||
|
pause_cd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CD_IO::IndexStatus.write({old_idx});
|
else if(cur_irq == CD_IO::Interrupt::DiskError) {
|
||||||
|
current_state = State::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No masking required because we can only write bit 0 - 2
|
||||||
|
CD_IO::IndexStatus = old_status;
|
||||||
return InterruptVerifierResult::ExecuteHandler;
|
return InterruptVerifierResult::ExecuteHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,27 +117,23 @@ namespace JabyEngine {
|
||||||
__syscall_ReturnFromException();
|
__syscall_ReturnFromException();
|
||||||
}
|
}
|
||||||
|
|
||||||
VolatilePOD<CD_IO::Interrupt::Type> last_interrupt{CD_IO::Interrupt::Type::None};
|
void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) {
|
||||||
InterrupCallback callback = {
|
cur_lba = file_info.get_lba();
|
||||||
.next = nullptr,
|
dst_lba = cur_lba + file_info.get_size_in_sectors();
|
||||||
.handler_function = reinterpret_cast<InterruptHandler>(interrupt_handler),
|
|
||||||
.verifier_function = interrupt_verifier
|
|
||||||
};
|
|
||||||
|
|
||||||
State read_file(FileInfo file_info, const SectorBufferAllocator& buffer_allocator) {
|
|
||||||
sector_allocator = buffer_allocator;
|
sector_allocator = buffer_allocator;
|
||||||
sectors_left = file_info.sectors;
|
|
||||||
|
|
||||||
|
Command::wait_completed();
|
||||||
CD_IO::PortIndex0::change_to();
|
CD_IO::PortIndex0::change_to();
|
||||||
Command::send_wait<CD_IO::PortIndex0>(CD_IO::Command::SetMode, DataSectorMode);
|
Command::send_wait<CD_IO::PortIndex0>(CD_IO::Command::SetMode, DataSectorMode);
|
||||||
|
|
||||||
const auto loc = CDTimeStamp::from(file_info);
|
read_cd(cur_lba);
|
||||||
Command::send_wait<CD_IO::PortIndex0>(CD_IO::Command::SetLoc, loc.get_min_cd(), loc.get_sec_cd(), loc.get_sector_cd());
|
}
|
||||||
Command::send<CD_IO::PortIndex0>(CD_IO::Command::ReadN);
|
|
||||||
|
|
||||||
printf("Now reading: %i\n", file_info.lba);
|
void continue_reading() {
|
||||||
printf("I'm not fully implemented! %s\n", __FUNCTION__);
|
if(current_state == State::BufferFull) {
|
||||||
return State::Error;
|
Command::wait_completed();
|
||||||
|
read_cd(cur_lba);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,116 @@
|
||||||
|
#include "../../../internal-include/CD/cd_internal.hpp"
|
||||||
#include <PSX/File/Processor/cd_file_processor.hpp>
|
#include <PSX/File/Processor/cd_file_processor.hpp>
|
||||||
#include <CD/cd_internal.hpp>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
void CDFileProcessor :: start_cur_job() {
|
static constexpr auto DisabledCircularBufferSize = 512;
|
||||||
using CD::internal::FileInfo;
|
|
||||||
|
void CDFileProcessor :: start_cur_job(const AutoLBAEntry* lba, const BufferConfiguration& buf_cfg) {
|
||||||
using CD::internal::SectorBufferAllocator;
|
using CD::internal::SectorBufferAllocator;
|
||||||
|
const auto configurate_for = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> FileProcessor::State {
|
||||||
|
const uint32_t* data_adr = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> const uint32_t* {
|
||||||
|
const auto disable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* overwrite_dst = nullptr) -> uint32_t* {
|
||||||
|
reinterpret_cast<uint8_t*>(this->circular_buffer.setup(reinterpret_cast<CD_IO::DataSector*>(work_area), size));
|
||||||
|
|
||||||
const auto& cur_lba = this->lba[this->jobs.files->rel_lba_idx];
|
this->lz4_decomp.disable();
|
||||||
|
return overwrite_dst ? overwrite_dst : reinterpret_cast<uint32_t*>(work_area);
|
||||||
|
};
|
||||||
|
|
||||||
CD::internal::read_file(FileInfo::from(cur_lba), SectorBufferAllocator::create(this, [](void* ctx) -> CD::internal::DataSector* {
|
const auto enable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* override_dst = nullptr) -> uint32_t* {
|
||||||
printf("Blubb?!\n");
|
uint8_t* dst_adr = reinterpret_cast<uint8_t*>(this->circular_buffer.setup(reinterpret_cast<CD_IO::DataSector*>(work_area), size));
|
||||||
return nullptr;
|
|
||||||
}));
|
if(override_dst) {
|
||||||
|
dst_adr = reinterpret_cast<uint8_t*>(override_dst);
|
||||||
|
}
|
||||||
|
|
||||||
printf(">>> CD needs to load LBA: %i -> %i\n", cur_lba.lba, cur_lba.size_words);
|
this->lz4_decomp.setup(dst_adr);
|
||||||
|
return reinterpret_cast<uint32_t*>(dst_adr);
|
||||||
|
};
|
||||||
|
|
||||||
|
if(file.type == CDFileType::CopyTo) {
|
||||||
|
return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count, file.payload.overlay.dst) : disable_lz4(file.payload.copy_to.dst, DisabledCircularBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count) : disable_lz4(buf_cfg.adr, DisabledCircularBufferSize);
|
||||||
|
}
|
||||||
|
}(file, buf_cfg, is_lz4);
|
||||||
|
|
||||||
|
switch(file.type) {
|
||||||
|
case CDFileType::SimpleTIM:
|
||||||
|
return FileProcessor::create(data_adr, file.payload.simple_tim);
|
||||||
|
|
||||||
|
case CDFileType::CopyTo:
|
||||||
|
default:
|
||||||
|
return FileProcessor::create(data_adr, Nothing());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto& cur_job = *this->jobs.files;
|
||||||
|
const auto& cur_lba = lba[cur_job.rel_lba_idx];
|
||||||
|
|
||||||
|
this->file_state = configurate_for(cur_job, buf_cfg, cur_lba.is_lz4());
|
||||||
|
CD::internal::read_file(cur_lba, SectorBufferAllocator::create(this,
|
||||||
|
[](void* ctx) -> CD_IO::DataSector* {
|
||||||
|
CDFileProcessor &self = *reinterpret_cast<CDFileProcessor*>(ctx);
|
||||||
|
return self.circular_buffer.allocate();
|
||||||
|
}));
|
||||||
|
|
||||||
|
printf(">>> CD needs to load LBA: %i -> %i (is LZ4: [%s])\n", cur_lba.get_lba(), cur_lba.get_size_in_sectors(), cur_lba.is_lz4() ? "Yes" : "No");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDFileProcessor :: setup(const volatile AutoLBAEntry* lba, JobArray jobs, uint8_t* work_area) {
|
bool CDFileProcessor :: process_data() {
|
||||||
this->lba = const_cast<const AutoLBAEntry*>(lba);
|
while(this->circular_buffer.has_data()) {
|
||||||
this->work_area = work_area;
|
ArrayRange<const uint8_t> cur_sector(reinterpret_cast<uint8_t*>(this->circular_buffer.get_next()->data), CD_IO::DataSector::SizeBytes);
|
||||||
this->jobs = jobs;
|
|
||||||
|
// v We can not know if there will be more data or not - but it also doesn't matter much for us
|
||||||
|
const auto result = this->lz4_decomp.process(cur_sector, false);
|
||||||
|
this->circular_buffer.pop();
|
||||||
|
|
||||||
CDFileProcessor::start_cur_job();
|
if(result) {
|
||||||
|
// Process the data in the tmp_area
|
||||||
|
if(this->file_state.process(result.bytes_ready) == Progress::Error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDFileProcessor :: setup(const volatile AutoLBAEntry* lba, JobArray jobs, const BufferConfiguration& buf_cfg) {
|
||||||
|
this->jobs = jobs;
|
||||||
|
CDFileProcessor::start_cur_job(const_cast<const AutoLBAEntry*>(lba), buf_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Progress CDFileProcessor :: process() {
|
Progress CDFileProcessor :: process() {
|
||||||
return Progress::Error;
|
const auto cur_state = CD::internal::read_current_state();
|
||||||
|
|
||||||
|
CDFileProcessor::process_data();
|
||||||
|
switch(cur_state) {
|
||||||
|
case CD::internal::State::Done:
|
||||||
|
/*
|
||||||
|
We are done now!
|
||||||
|
The user decides if he wants the next value
|
||||||
|
*/
|
||||||
|
//while(this->file_state.process(0) != Progress::Done);
|
||||||
|
return Progress::Done;
|
||||||
|
|
||||||
|
case CD::internal::State::BufferFull:
|
||||||
|
/* We processd data and unpause the CD drive */
|
||||||
|
CD::internal::continue_reading();
|
||||||
|
return Progress::InProgress;
|
||||||
|
|
||||||
|
case CD::internal::State::Reading:
|
||||||
|
return Progress::InProgress;
|
||||||
|
|
||||||
|
case CD::internal::State::Error:
|
||||||
|
default:
|
||||||
|
/* Error for real */
|
||||||
|
return Progress::Error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include "simplehelper.hpp"
|
||||||
|
|
||||||
|
namespace JabyEngine {
|
||||||
|
namespace FileProcessor {
|
||||||
|
struct NothingState {
|
||||||
|
};
|
||||||
|
|
||||||
|
static Progress parse_nothing(State::Configuration& config, NothingState& state) {
|
||||||
|
return Progress::Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
State create(const uint32_t* data_adr, const Nothing& nothing) {
|
||||||
|
return State::from(NothingState(), reinterpret_cast<const uint8_t*>(data_adr), parse_nothing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,12 +10,10 @@ namespace JabyEngine {
|
||||||
namespace Helper {
|
namespace Helper {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void simple_read(T& dst, State::Configuration& config) {
|
static void simple_read(T& dst, State::Configuration& config) {
|
||||||
static constexpr size_t UINT32_SIZE = (sizeof(T)/sizeof(uint32_t));
|
static constexpr size_t T_SIZE = sizeof(T);
|
||||||
|
|
||||||
dst = *reinterpret_cast<const T*>(config.data_adr);
|
dst = *reinterpret_cast<const T*>(config.data_adr);
|
||||||
config.processed(UINT32_SIZE);
|
config.processed(T_SIZE);
|
||||||
|
|
||||||
static_assert((UINT32_SIZE*sizeof(uint32_t)) == sizeof(T));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "../../../include/GPU/gpu_internal.hpp"
|
#include "../../../internal-include/GPU/gpu_internal.hpp"
|
||||||
#include "simplehelper.hpp"
|
#include "simplehelper.hpp"
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -50,9 +50,10 @@ namespace JabyEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Progress parse_data(State::Configuration& config, SimpleTIMState& state) {
|
static Progress parse_data(State::Configuration& config, SimpleTIMState& state) {
|
||||||
const auto words_to_use = (config.data_word_size > state.words_left) ? state.words_left : config.data_word_size;
|
const auto config_data_words = (config.data_bytes/sizeof(uint32_t));
|
||||||
bool is_last = (words_to_use == state.words_left);
|
const auto words_to_use = (config_data_words > state.words_left) ? state.words_left : config_data_words;
|
||||||
auto block_count = (words_to_use >> 4);
|
bool is_last = (words_to_use == state.words_left);
|
||||||
|
auto block_count = (words_to_use >> 4);
|
||||||
|
|
||||||
while(block_count > 0) {
|
while(block_count > 0) {
|
||||||
const auto block_send = (block_count > UI16_MAX) ? UI16_MAX : block_count;
|
const auto block_send = (block_count > UI16_MAX) ? UI16_MAX : block_count;
|
||||||
|
@ -75,7 +76,7 @@ namespace JabyEngine {
|
||||||
GPU::internal::DMA::end();
|
GPU::internal::DMA::end();
|
||||||
|
|
||||||
state.words_left = 0;
|
state.words_left = 0;
|
||||||
config.processed(words_to_use);
|
config.processed(words_to_use*sizeof(uint32_t));
|
||||||
|
|
||||||
return Progress::Done;
|
return Progress::Done;
|
||||||
}
|
}
|
||||||
|
@ -84,13 +85,13 @@ namespace JabyEngine {
|
||||||
const auto words_used = (words_to_use & ~0b1111);
|
const auto words_used = (words_to_use & ~0b1111);
|
||||||
|
|
||||||
state.words_left -= words_used;
|
state.words_left -= words_used;
|
||||||
config.processed(words_used);
|
config.processed(words_used*sizeof(uint32_t));
|
||||||
return Progress::InProgress;
|
return Progress::InProgress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Progress switch_state_parse_data(State::Configuration& config, SimpleTIMState& state) {
|
static Progress switch_state_parse_data(State::Configuration& config, SimpleTIMState& state) {
|
||||||
set_gpu_receive_data(config.data_adr, state, state.size_info.getTextureWidth(), state.size_info.getTextureHeight());
|
set_gpu_receive_data(reinterpret_cast<const uint32_t*>(config.data_adr), state, state.size_info.getTextureWidth(), state.size_info.getTextureHeight());
|
||||||
return Helper::exchange_and_execute_process_function(parse_data, config, state);
|
return Helper::exchange_and_execute_process_function(parse_data, config, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,13 +106,13 @@ namespace JabyEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Progress parse_header(State::Configuration& config, SimpleTIMState& state) {
|
static Progress parse_header(State::Configuration& config, SimpleTIMState& state) {
|
||||||
if(config.data_word_size >= (sizeof(SimpleTIMSize)/sizeof(uint32_t))) {
|
if(config.data_bytes >= sizeof(SimpleTIMSize)) {
|
||||||
Helper::simple_read(state.size_info, config);
|
Helper::simple_read(state.size_info, config);
|
||||||
|
|
||||||
//Check if we have a clut to care about
|
//Check if we have a clut to care about
|
||||||
if(state.size_info.getClutWidth() > 0) {
|
if(state.size_info.getClutWidth() > 0) {
|
||||||
//CLUTs are 16bit full color anyway
|
//CLUTs are 16bit full color anyway
|
||||||
set_gpu_receive_data(config.data_adr, state, state.size_info.getClutWidth(), state.size_info.getClutHeight());
|
set_gpu_receive_data(reinterpret_cast<const uint32_t*>(config.data_adr), state, state.size_info.getClutWidth(), state.size_info.getClutHeight());
|
||||||
return Helper::exchange_and_execute_process_function(parse_clut, config, state);
|
return Helper::exchange_and_execute_process_function(parse_clut, config, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +126,7 @@ namespace JabyEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
State create(const uint32_t* data_adr, const SimpleTIM& file) {
|
State create(const uint32_t* data_adr, const SimpleTIM& file) {
|
||||||
return State::from(SimpleTIMState(file), data_adr, parse_header);
|
return State::from(SimpleTIMState(file), reinterpret_cast<const uint8_t*>(data_adr), parse_header);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "../include/GPU/gpu_internal.hpp"
|
#include "../../internal-include/GPU/gpu_internal.hpp"
|
||||||
|
|
||||||
namespace JabyEngine {
|
namespace JabyEngine {
|
||||||
namespace GPU {
|
namespace GPU {
|
||||||
|
@ -16,7 +16,7 @@ namespace JabyEngine {
|
||||||
void Screen :: exchange_buffer_and_display() {
|
void Screen :: exchange_buffer_and_display() {
|
||||||
GPU::internal::set_draw_area(0, (Display::Height*PublicScreenClass::CurrentDisplayAreaID));
|
GPU::internal::set_draw_area(0, (Display::Height*PublicScreenClass::CurrentDisplayAreaID));
|
||||||
PublicScreenClass::CurrentDisplayAreaID ^= 1;
|
PublicScreenClass::CurrentDisplayAreaID ^= 1;
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::DisplayArea(0, (Display::Height*PublicScreenClass::CurrentDisplayAreaID)));
|
GPU_IO::GP1 = GPU_IO::Command::DisplayArea(0, (Display::Height*PublicScreenClass::CurrentDisplayAreaID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,13 +25,13 @@ namespace JabyEngine {
|
||||||
x += 78;
|
x += 78;
|
||||||
y += 43;
|
y += 43;
|
||||||
|
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::HorizontalDisplayRange((x << 3), (x + Display::Width) << 3));
|
GPU_IO::GP1 = GPU_IO::Command::HorizontalDisplayRange((x << 3), (x + Display::Width) << 3);
|
||||||
GPU_IO::GP1.write(GPU_IO::Command::GP1::VerticalDisplayRange(y, y + Display::Height));
|
GPU_IO::GP1 = GPU_IO::Command::VerticalDisplayRange(y, y + Display::Height);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void Screen :: set_offset(uint16_t x, uint16_t y) {
|
void Screen :: set_offset(uint16_t x, uint16_t y) {
|
||||||
GP1.write(Command::GP1::HorizontalDisplayRange(x, (x + Display::Width*8)));
|
GPU_IO::GP1 = GPU_IO::Command::HorizontalDisplayRange(x, (x + Display::Width*8));
|
||||||
GP1.write(Command::GP1::VerticalDisplayRange(y - (ScanlinesV/2), y + (ScanlinesV/2)));
|
GPU_IO::GP1 = GPU_IO::Command::VerticalDisplayRange(y - (ScanlinesV/2), y + (ScanlinesV/2));
|
||||||
}
|
}
|
||||||
#endif //USE_NO$PSX
|
#endif //USE_NO$PSX
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern void main();
|
||||||
|
|
||||||
|
namespace JabyEngine {
|
||||||
|
// Executes the game
|
||||||
|
void __no_return run() {
|
||||||
|
main();
|
||||||
|
printf("Stop!!\n");
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,29 +0,0 @@
|
||||||
#include "../include/BootLoader/boot_loader.hpp"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
namespace JabyEngine {
|
|
||||||
static NextRoutine execute(NextRoutine routine) {
|
|
||||||
// Support currently only direct call
|
|
||||||
return reinterpret_cast<MainRoutine>((routine.value & ~JabyEngine::NextRoutine::OverlayBit))();
|
|
||||||
}
|
|
||||||
|
|
||||||
void start() {
|
|
||||||
NextRoutine next_routine = JabyEngine::NextRoutine::from(boot::Start::setup);
|
|
||||||
|
|
||||||
printf("Starting Planschbecken 0x%p\n", next_routine.value);
|
|
||||||
while(true) {
|
|
||||||
if(next_routine.is_null()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(next_routine.is_overlay()) {
|
|
||||||
printf("Overlay not supported yet!\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_routine = execute(next_routine);
|
|
||||||
}
|
|
||||||
printf("Stop!\n");
|
|
||||||
while(true);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
set bin_projects=psxcdgen psxcdread psxcdgen_ex
|
set bin_projects=psxcdgen psxcdread psxcdgen_ex wslpath
|
||||||
set bin_linux_projects=cpp_out jaby_engine_fconv mkoverlay
|
set bin_linux_projects=cpp_out jaby_engine_fconv mkoverlay
|
||||||
set clean_projects=cdtypes
|
set clean_projects=cdtypes
|
||||||
set clean_projects_linux=tool_helper
|
set clean_projects_linux=tool_helper
|
|
@ -59,7 +59,7 @@
|
||||||
{
|
{
|
||||||
"id": "project",
|
"id": "project",
|
||||||
"type": "pickString",
|
"type": "pickString",
|
||||||
"options": ["cdtypes", "cpp_out", "jaby_engine_fconv", "mkoverlay", "psxcdgen", "psxcdgen_ex", "psxcdread", "tool_helper"],
|
"options": ["cdtypes", "cpp_out", "jaby_engine_fconv", "mkoverlay", "psxcdgen", "psxcdgen_ex", "psxcdread", "tool_helper", "wslpath"],
|
||||||
"description": "project to build"
|
"description": "project to build"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,13 +58,23 @@ fn write_section(output: &mut Output, sections: &Vec<OverlaySection>, add_end_na
|
||||||
for section in sections {
|
for section in sections {
|
||||||
writeln!(output, "\t\t.{} {{", section.name)?;
|
writeln!(output, "\t\t.{} {{", section.name)?;
|
||||||
writeln!(output, "\t\t\t__{}_start = .;", section.name)?;
|
writeln!(output, "\t\t\t__{}_start = .;", section.name)?;
|
||||||
section.file_pattern.iter().try_for_each(|patr| writeln!(output, "\t\t\tKEEP({}(.header))", patr))?;
|
|
||||||
writeln!(output, "\t\t\t__{}_lbas = .;", section.name)?;
|
writeln!(output, "\t\t\t__{}_lbas = .;", section.name)?;
|
||||||
section.file_pattern.iter().try_for_each(|patr| writeln!(output, "\t\t\tKEEP({}(.header.lbas))", patr))?;
|
section.file_pattern.iter().try_for_each(|patr| writeln!(output, "\t\t\tKEEP({}(.header.lbas))", patr))?;
|
||||||
writeln!(output, "\t\t\t__{}_ctor = .;", section.name)?;
|
writeln!(output, "\t\t\t__{}_ctor = .;", section.name)?;
|
||||||
|
|
||||||
for section_type in [".text.startup._GLOBAL__*", ".ctors", ".text.*", ".rodata*", ".sdata*", ".data*", ".sbss*", ".bss*"] {
|
for (section_type, keep) in [(".text.startup._GLOBAL__*", false), (".ctors", false), (".text.*", false), (".rodata*", false), (".sdata*", false), (".data*", false), (".sbss*", false), (".bss*", false), (".keep.dummy", true)] {
|
||||||
section.file_pattern.iter().try_for_each(|patr| writeln!(output, "\t\t\t{}({})", patr, section_type))?;
|
section.file_pattern.iter().try_for_each(|patr| {
|
||||||
|
let section_entry = format!("{}({})", patr, section_type);
|
||||||
|
|
||||||
|
write!(output, "\t\t\t")?;
|
||||||
|
if keep {
|
||||||
|
writeln!(output, "KEEP({})", section_entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
writeln!(output, "{}", section_entry)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if add_end_name {
|
if add_end_name {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "psxcdgen_ex"
|
name = "psxcdgen_ex"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
|
@ -2,6 +2,12 @@ use super::Error;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
mod xml;
|
mod xml;
|
||||||
|
|
||||||
|
pub enum LZ4State {
|
||||||
|
None,
|
||||||
|
AlreadyCompressed,
|
||||||
|
Compress,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Configuration {
|
pub struct Configuration {
|
||||||
pub publisher: Option<String>,
|
pub publisher: Option<String>,
|
||||||
pub license_path: Option<PathBuf>,
|
pub license_path: Option<PathBuf>,
|
||||||
|
@ -17,6 +23,7 @@ impl Configuration {
|
||||||
pub struct CommonProperties {
|
pub struct CommonProperties {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub is_hidden: bool,
|
pub is_hidden: bool,
|
||||||
|
pub lz4_state: LZ4State,
|
||||||
pub padded_size: Option<usize>,
|
pub padded_size: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,14 @@ use std::path::PathBuf;
|
||||||
use tool_helper::{format_if_error, path_with_env_from};
|
use tool_helper::{format_if_error, path_with_env_from};
|
||||||
use crate::config_reader::Directory;
|
use crate::config_reader::Directory;
|
||||||
|
|
||||||
use super::{CommonProperties, Configuration, Error, File, FileKind};
|
use super::{CommonProperties, Configuration, Error, File, FileKind, LZ4State};
|
||||||
|
|
||||||
mod attribute_names {
|
mod attribute_names {
|
||||||
pub const NAME: &'static str = "name";
|
pub const NAME: &'static str = "name";
|
||||||
pub const HIDDEN: &'static str = "hidden";
|
pub const HIDDEN: &'static str = "hidden";
|
||||||
pub const PADDED_SIZE: &'static str = "padded_size";
|
pub const PADDED_SIZE: &'static str = "padded_size";
|
||||||
pub const LBA_SOURCE: &'static str = "lba_source";
|
pub const LBA_SOURCE: &'static str = "lba_source";
|
||||||
|
pub const LZ4_STATE: &'static str = "lz4";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(xml: String) -> Result<Configuration, Error> {
|
pub fn parse(xml: String) -> Result<Configuration, Error> {
|
||||||
|
@ -57,27 +58,28 @@ fn parse_description(description: roxmltree::Node, config: &mut Configuration) -
|
||||||
|
|
||||||
fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> {
|
fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> {
|
||||||
fn parse_regular_file(file: roxmltree::Node, is_hidden: bool) -> Result<File, Error> {
|
fn parse_regular_file(file: roxmltree::Node, is_hidden: bool) -> Result<File, Error> {
|
||||||
let common = read_common_properties(&file, is_hidden)?;
|
let common = read_common_properties(&file, is_hidden, None)?;
|
||||||
let path = path_from_node(&file, &common.name)?;
|
let path = path_from_node(&file, &common.name)?;
|
||||||
|
|
||||||
Ok(File{common, path, kind: FileKind::Regular})
|
Ok(File{common, path, kind: FileKind::Regular})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_main_file(file: roxmltree::Node, is_hidden: bool) -> Result<File, Error> {
|
fn parse_main_file(file: roxmltree::Node) -> Result<File, Error> {
|
||||||
if let Some(lba_path) = file.attribute(attribute_names::LBA_SOURCE) {
|
if let Some(lba_path) = file.attribute(attribute_names::LBA_SOURCE) {
|
||||||
let common = read_common_properties(&file, is_hidden)?;
|
let common = read_common_properties(&file, false, Some(LZ4State::None))?;
|
||||||
let path = path_from_node(&file, &common.name)?;
|
let path = path_from_node(&file, &common.name)?;
|
||||||
|
|
||||||
Ok(File{common, path, kind: FileKind::Main(PathBuf::from(lba_path))})
|
Ok(File{common, path, kind: FileKind::Main(PathBuf::from(lba_path))})
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
parse_regular_file(file, is_hidden)
|
parse_regular_file(file, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_overlay_file(file: roxmltree::Node, is_hidden: bool) -> Result<File, Error> {
|
fn parse_overlay_file(file: roxmltree::Node, is_hidden: bool) -> Result<File, Error> {
|
||||||
let common = read_common_properties(&file, is_hidden)?;
|
// v they will be compressed automatically
|
||||||
|
let common = read_common_properties(&file, is_hidden, Some(LZ4State::AlreadyCompressed))?;
|
||||||
let path = path_from_node(&file, &common.name)?;
|
let path = path_from_node(&file, &common.name)?;
|
||||||
|
|
||||||
Ok(File{common, path, kind: FileKind::Overlay(PathBuf::from(file.attribute(attribute_names::LBA_SOURCE).unwrap_or_default()))})
|
Ok(File{common, path, kind: FileKind::Overlay(PathBuf::from(file.attribute(attribute_names::LBA_SOURCE).unwrap_or_default()))})
|
||||||
|
@ -88,7 +90,7 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(),
|
||||||
if node.is_element() {
|
if node.is_element() {
|
||||||
match node.tag_name().name() {
|
match node.tag_name().name() {
|
||||||
"File" => root.add_file(parse_regular_file(node, is_hidden)?),
|
"File" => root.add_file(parse_regular_file(node, is_hidden)?),
|
||||||
"Main" => root.add_file(parse_main_file(node, is_hidden)?),
|
"Main" => root.add_file(parse_main_file(node)?),
|
||||||
"Overlay" => root.add_file(parse_overlay_file(node, is_hidden)?),
|
"Overlay" => root.add_file(parse_overlay_file(node, is_hidden)?),
|
||||||
"Directory" => {
|
"Directory" => {
|
||||||
is_hidden |= parse_boolean_attribute(&node, attribute_names::HIDDEN)?;
|
is_hidden |= parse_boolean_attribute(&node, attribute_names::HIDDEN)?;
|
||||||
|
@ -108,10 +110,31 @@ fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(),
|
||||||
parse_file_system(track, &mut config.root, false)
|
parse_file_system(track, &mut config.root, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_common_properties(xml: &roxmltree::Node, is_hidden: bool) -> Result<CommonProperties, Error> {
|
fn read_common_properties(xml: &roxmltree::Node, is_hidden: bool, force_lz4_state: Option<LZ4State>) -> Result<CommonProperties, Error> {
|
||||||
|
let lz4_state = {
|
||||||
|
if let Some(forced_lz4_state) = force_lz4_state {
|
||||||
|
forced_lz4_state
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
if let Some(state_str) = xml.attribute(attribute_names::LZ4_STATE) {
|
||||||
|
match state_str.to_lowercase().as_str() {
|
||||||
|
"yes" => LZ4State::Compress,
|
||||||
|
"already" => LZ4State::AlreadyCompressed,
|
||||||
|
_ => LZ4State::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
LZ4State::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(CommonProperties{
|
Ok(CommonProperties{
|
||||||
name: String::from(xml.attribute(attribute_names::NAME).unwrap_or_default()),
|
name: String::from(xml.attribute(attribute_names::NAME).unwrap_or_default()),
|
||||||
is_hidden: is_hidden | parse_boolean_attribute(&xml, attribute_names::HIDDEN)?,
|
is_hidden: is_hidden | parse_boolean_attribute(&xml, attribute_names::HIDDEN)?,
|
||||||
|
lz4_state,
|
||||||
padded_size: read_padded_size(&xml)?
|
padded_size: read_padded_size(&xml)?
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,11 @@ pub mod encoder;
|
||||||
pub mod file_writer;
|
pub mod file_writer;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
use config_reader::LZ4State;
|
||||||
use encoder::{LbaCalculatorFunction, LengthCalculatorFunction};
|
use encoder::{LbaCalculatorFunction, LengthCalculatorFunction};
|
||||||
use tool_helper::{format_if_error, Output, read_file};
|
use tool_helper::{format_if_error, Output, read_file};
|
||||||
use types::{layout::Layout, CDDesc, Directory, File, FileType, FileSystemMap, Properties, SharedPtr};
|
use types::{layout::Layout, CDDesc, Directory, File, FileType, FileSystemMap, Properties, SharedPtr};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub type LBAEmbeddedFiles = Vec<SharedPtr<File>>;
|
pub type LBAEmbeddedFiles = Vec<SharedPtr<File>>;
|
||||||
|
|
||||||
|
@ -156,16 +158,30 @@ fn parse_configuration(config: config_reader::Configuration) -> Result<(CDDesc,
|
||||||
},
|
},
|
||||||
|
|
||||||
config_reader::DirMember::File(file) => {
|
config_reader::DirMember::File(file) => {
|
||||||
|
let lz4_state = file.common.lz4_state;
|
||||||
let (mut desc_file, needs_treatment) = {
|
let (mut desc_file, needs_treatment) = {
|
||||||
|
fn handle_file_load(file_path: &PathBuf, lz4_state: &LZ4State) -> Result<Vec<u8>, Error> {
|
||||||
|
let file_content = read_file(file_path)?;
|
||||||
|
|
||||||
|
if matches!(lz4_state, LZ4State::Compress) {
|
||||||
|
tool_helper::compress::psx_default::lz4(&file_content)
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
Ok(file_content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match file.kind {
|
match file.kind {
|
||||||
config_reader::FileKind::Regular => (types::File::new_regular(file.common.name.as_str(), read_file(&file.path)?)?, false),
|
config_reader::FileKind::Regular => (types::File::new_regular(file.common.name.as_str(), handle_file_load(&file.path, &lz4_state)?)?, false),
|
||||||
config_reader::FileKind::Main(lba_source) => (types::overlay::load_for_main(file.common.name.as_str(), read_file(&file.path)?, lba_source)?, true),
|
config_reader::FileKind::Main(lba_source) => (types::overlay::load_for_main(file.common.name.as_str(), handle_file_load(&file.path, &lz4_state)?, lba_source)?, true),
|
||||||
config_reader::FileKind::Overlay(lba_source) => (types::overlay::load_from(file.common.name.as_str(), file.path, lba_source)?, true),
|
config_reader::FileKind::Overlay(lba_source) => (types::overlay::load_from(file.common.name.as_str(), &file.path, lba_source)?, true),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
desc_file.properties.padded_size_bytes = file.common.padded_size;
|
desc_file.properties.padded_size_bytes = file.common.padded_size;
|
||||||
desc_file.properties.is_hidden = file.common.is_hidden;
|
desc_file.properties.is_hidden = file.common.is_hidden;
|
||||||
|
desc_file.properties.is_lz4 = !matches!(lz4_state, LZ4State::None);
|
||||||
|
|
||||||
let new_file = dst_dir.add_file(desc_file);
|
let new_file = dst_dir.add_file(desc_file);
|
||||||
if needs_treatment {
|
if needs_treatment {
|
||||||
|
|
|
@ -315,7 +315,8 @@ pub struct Properties {
|
||||||
pub(super) lba: LBA,
|
pub(super) lba: LBA,
|
||||||
pub(super) size_bytes: usize,
|
pub(super) size_bytes: usize,
|
||||||
pub(super) padded_size_bytes: Option<usize>,
|
pub(super) padded_size_bytes: Option<usize>,
|
||||||
pub(super) is_hidden: bool
|
pub(super) is_hidden: bool,
|
||||||
|
pub(super) is_lz4: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Properties {
|
impl Properties {
|
||||||
|
@ -340,7 +341,7 @@ impl Properties {
|
||||||
|
|
||||||
impl Default for Properties {
|
impl Default for Properties {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Properties{lba: LBA::default(), size_bytes: 0, padded_size_bytes: None, is_hidden: false}
|
Properties{lba: LBA::default(), size_bytes: 0, padded_size_bytes: None, is_hidden: false, is_lz4: false}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,56 +2,50 @@ use super::{layout::Layout, File, FileSystemMap};
|
||||||
use super::super::encoder::LengthCalculatorFunction;
|
use super::super::encoder::LengthCalculatorFunction;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use no_comment::{IntoWithoutComments as _, languages};
|
use no_comment::{IntoWithoutComments as _, languages};
|
||||||
use tool_helper::{Error, format_if_error, read_file, format_if_error_drop_cause};
|
use tool_helper::{bits::{Bit, BitRange}, Error, format_if_error, read_file, read_file_to_string, format_if_error_drop_cause};
|
||||||
|
|
||||||
pub type LBANameVec = Vec<String>;
|
pub type LBANameVec = Vec<String>;
|
||||||
|
|
||||||
mod main;
|
mod main;
|
||||||
|
|
||||||
#[repr(packed)]
|
|
||||||
struct OverlayHeader {
|
|
||||||
_start_adr: u32,
|
|
||||||
lba_count: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OverlayHeader {
|
|
||||||
pub fn read_lba_count(&self) -> usize {
|
|
||||||
u16::from_le(self.lba_count) as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
struct LBAEntry {
|
struct LBAEntry {
|
||||||
lba: u16,
|
raw: u32,
|
||||||
size_words: u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LBAEntry {
|
impl LBAEntry {
|
||||||
pub fn write_entry(&mut self, lba: u16, mut size_bytes: usize) -> Result<(), Error> {
|
const SIZE_IN_SECTOR_RANGE:BitRange = BitRange::from_to(22, 31);
|
||||||
const WORD_SIZE:usize = std::mem::size_of::<u32>();
|
const IS_LZ4_COMPRESSED:Bit = Bit::at(19);
|
||||||
|
const LBA_VALUE_RANGE:BitRange = BitRange::from_to(0, 18);
|
||||||
|
|
||||||
if self.lba != 0 || self.size_words != 0 {
|
pub fn write_entry(&mut self, lba: usize, size_bytes: usize, is_lz4: bool) -> Result<(), Error> {
|
||||||
|
if lba > Self::LBA_VALUE_RANGE.max_value() {
|
||||||
|
return Err(Error::from_text(format!("LBA of value {} is impossible and can not be encoded! Maximum LBA value is: {}", lba, Self::LBA_VALUE_RANGE.max_value())));
|
||||||
|
}
|
||||||
|
|
||||||
|
let size_in_sectors = cdtypes::types::helper::sector_count_mode2_form1(size_bytes);
|
||||||
|
if size_in_sectors > Self::SIZE_IN_SECTOR_RANGE.max_value() {
|
||||||
|
return Err(Error::from_text(format!("{} sectors can not be encoded into 10bit", size_in_sectors)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let lba = usize::from_ne_bytes(lba.to_le_bytes());
|
||||||
|
let size_in_sectors = usize::from_ne_bytes(size_in_sectors.to_le_bytes());
|
||||||
|
|
||||||
|
if self.raw != 0 {
|
||||||
return Err(Error::from_str("LBA Entry will overwrite non-zero value!\nIs no space allocated for the LBA Entries?"));
|
return Err(Error::from_str("LBA Entry will overwrite non-zero value!\nIs no space allocated for the LBA Entries?"));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_bytes = (size_bytes + (WORD_SIZE - 1))/WORD_SIZE;
|
let new_raw = Self::LBA_VALUE_RANGE.or_value(0, lba);
|
||||||
|
let new_raw = Self::SIZE_IN_SECTOR_RANGE.or_value(new_raw, size_in_sectors);
|
||||||
if (size_bytes as u16) as usize != size_bytes {
|
let new_raw = Self::IS_LZ4_COMPRESSED.or_value(new_raw, is_lz4);
|
||||||
return Err(Error::from_text(format!("{} words can not be encoded into 16bit", size_bytes)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let lba = lba.to_le_bytes();
|
|
||||||
let size_bytes = (size_bytes as u16).to_le_bytes();
|
|
||||||
|
|
||||||
self.lba = u16::from_ne_bytes(lba);
|
|
||||||
self.size_words = u16::from_ne_bytes(size_bytes);
|
|
||||||
|
|
||||||
|
self.raw = new_raw as u32;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_from(file_name: &str, file_path: PathBuf, lba_source: PathBuf) -> Result<File, Error> {
|
pub fn load_from(file_name: &str, file_path: &PathBuf, lba_source: PathBuf) -> Result<File, Error> {
|
||||||
let content = load_content(&file_path)?;
|
let content = read_file(file_path)?;
|
||||||
let lba_names = load_lba_names(lba_source)?;
|
let lba_names = load_lba_names(lba_source)?;
|
||||||
let content_size = format_if_error!(tool_helper::compress::psx_default::lz4(&content), "Compressing {} failed with \"{error_text}\"", file_path.to_string_lossy())?.len();
|
let content_size = format_if_error!(tool_helper::compress::psx_default::lz4(&content), "Compressing {} failed with \"{error_text}\"", file_path.to_string_lossy())?.len();
|
||||||
|
|
||||||
|
@ -63,15 +57,11 @@ pub fn load_for_main(file_name: &str, content: Vec<u8>, lba_source: PathBuf) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_content(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<Vec<u8>, Error> {
|
pub fn update_content(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<Vec<u8>, Error> {
|
||||||
let (lba_header, lba_count) = skip_to_lba_header(content);
|
let lba_header = skip_to_lba_header(content);
|
||||||
let lba_header = unsafe{std::slice::from_raw_parts_mut(lba_header.as_mut_ptr() as *mut LBAEntry, lba_count)};
|
let lba_header = unsafe{std::slice::from_raw_parts_mut(lba_header.as_mut_ptr() as *mut LBAEntry, lba_names.len())};
|
||||||
|
|
||||||
for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes)| {
|
for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes), is_lz4| {
|
||||||
if idx >= lba_count {
|
lba_header[idx].write_entry(lba, bytes, is_lz4)
|
||||||
return Err(Error::from_text(format!("Trying to write more LBAs then there is space!")));
|
|
||||||
}
|
|
||||||
|
|
||||||
lba_header[idx].write_entry(lba, bytes)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(tool_helper::compress::psx_default::lz4(content)?)
|
Ok(tool_helper::compress::psx_default::lz4(content)?)
|
||||||
|
@ -80,20 +70,22 @@ pub fn update_content(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &
|
||||||
pub fn update_content_for_main(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<Vec<u8>, Error> {
|
pub fn update_content_for_main(content: &mut Vec<u8>, lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction) -> Result<Vec<u8>, Error> {
|
||||||
let lba_header = unsafe{std::slice::from_raw_parts_mut(main::skip_to_lba_area(content).as_mut_ptr() as *mut LBAEntry, lba_names.len())};
|
let lba_header = unsafe{std::slice::from_raw_parts_mut(main::skip_to_lba_area(content).as_mut_ptr() as *mut LBAEntry, lba_names.len())};
|
||||||
|
|
||||||
for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes)| {
|
for_each_lba_name(lba_names, file_map, length_func, |idx, (lba, bytes), is_lz4| {
|
||||||
lba_header[idx].write_entry(lba, bytes)
|
lba_header[idx].write_entry(lba, bytes, is_lz4)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(content.clone())
|
Ok(content.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_each_lba_name<F: FnMut(usize, (u16, usize)) -> Result<(), Error>>(lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction, mut functor: F) -> Result<(), Error> {
|
fn for_each_lba_name<F: FnMut(usize, (usize, usize), bool) -> Result<(), Error>>(lba_names: &LBANameVec, file_map: &FileSystemMap, length_func: LengthCalculatorFunction, mut functor: F) -> Result<(), Error> {
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
for lba_name in lba_names {
|
for lba_name in lba_names {
|
||||||
if let Some(file) = file_map.get(lba_name) {
|
if let Some(file) = file_map.get(lba_name) {
|
||||||
let (lba, bytes) = (format_if_error_drop_cause!(file.try_borrow(), "Failed accessing file \"{}\" for writing LBA information.\nNote: You can not inject the LBA information of a file into itself.", lba_name)?.get_absolute_lba(), length_func(&Layout::File(file.clone())).bytes);
|
let file_ref = format_if_error_drop_cause!(file.try_borrow(), "Failed accessing file \"{}\" for writing LBA information.\nNote: You can not inject the LBA information of a file into itself.", lba_name)?;
|
||||||
|
let (lba, bytes) = (file_ref.get_absolute_lba(), length_func(&Layout::File(file.clone())).bytes);
|
||||||
|
let is_lz4 = file_ref.properties.is_lz4;
|
||||||
|
|
||||||
functor(idx, (lba as u16, bytes.ok_or(Error::from_text(format!("{} does not contain a size!", lba_name)))?))?;
|
functor(idx, (lba, bytes.ok_or(Error::from_text(format!("{} does not contain a size!", lba_name)))?), is_lz4)?;
|
||||||
idx += 1;
|
idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,34 +97,10 @@ fn for_each_lba_name<F: FnMut(usize, (u16, usize)) -> Result<(), Error>>(lba_nam
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_content(file_path: &PathBuf) -> Result<Vec<u8>, Error> {
|
fn skip_to_lba_header(content: &mut Vec<u8>) -> &mut [u8] {
|
||||||
let mut content = read_file(&file_path)?;
|
let overlay_header_size = 0;
|
||||||
|
|
||||||
if content.len() < std::mem::size_of::<OverlayHeader>() {
|
&mut content[overlay_header_size..]
|
||||||
return Err(Error::from_text(format!("Overlay {} has no header!", file_path.to_string_lossy())));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (lba_header, lba_count) = skip_to_lba_header(&mut content);
|
|
||||||
if lba_header.is_empty() {
|
|
||||||
return Err(Error::from_text(format!("LBA header of overlay {} is smaller then {} elements", file_path.to_string_lossy(), lba_count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
for byte in lba_header {
|
|
||||||
*byte = count as u8;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(content)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn skip_to_lba_header(content: &mut Vec<u8>) -> (&mut [u8], usize) {
|
|
||||||
let overlay_header_size = std::mem::size_of::<OverlayHeader>();
|
|
||||||
|
|
||||||
let lba_count = unsafe{std::mem::transmute::<&u8, &OverlayHeader>(&content[0])}.read_lba_count();
|
|
||||||
let lba_header_size = lba_count*std::mem::size_of::<LBAEntry>();
|
|
||||||
|
|
||||||
(&mut content[overlay_header_size..(overlay_header_size+lba_header_size)], lba_count)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_lba_names(lba_source: PathBuf) -> Result<LBANameVec, Error> {
|
fn load_lba_names(lba_source: PathBuf) -> Result<LBANameVec, Error> {
|
||||||
|
@ -152,7 +120,7 @@ fn load_lba_names(lba_source: PathBuf) -> Result<LBANameVec, Error> {
|
||||||
Ok(file[start..end].to_owned())
|
Ok(file[start..end].to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = std::fs::read_to_string(&lba_source)?.chars().without_comments(languages::c()).collect::<String>();
|
let file = read_file_to_string(&lba_source)?.chars().without_comments(languages::c()).collect::<String>();
|
||||||
let file = get_part_of_interest(file, &lba_source)?;
|
let file = get_part_of_interest(file, &lba_source)?;
|
||||||
let mut lba_names = Vec::new();
|
let mut lba_names = Vec::new();
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,43 @@
|
||||||
pub struct BitRange {
|
pub struct BitRange {
|
||||||
pub start: usize,
|
start: usize,
|
||||||
pub len: usize,
|
length: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitRange {
|
impl BitRange {
|
||||||
pub const fn from_to(start: usize, end: usize) -> BitRange {
|
pub const fn from_to(start_bit: usize, end_bit: usize) -> Self {
|
||||||
BitRange{start, len: (end - start + 1)}
|
Self{start: start_bit, length: (end_bit - start_bit) + 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn get_mask(&self) -> usize {
|
||||||
|
self.max_value()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn max_value(&self) -> usize {
|
||||||
|
(1 << self.length) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn or_value(&self, dst_value: usize, value: usize) -> usize {
|
||||||
|
dst_value | ((value & self.get_mask()) << self.start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Bit {
|
||||||
|
pos: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bit {
|
||||||
|
pub const fn at(pos: usize) -> Self {
|
||||||
|
Bit{pos}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn or_value(&self, dst_value: usize, is_set: bool) -> usize {
|
||||||
|
if is_set {
|
||||||
|
dst_value | (1 << self.pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
dst_value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +45,7 @@ macro_rules! create_bit_functions {
|
||||||
($type_val:ty) => {
|
($type_val:ty) => {
|
||||||
paste::item! {
|
paste::item! {
|
||||||
const fn [< get_mask_ $type_val >](range: &BitRange) -> $type_val {
|
const fn [< get_mask_ $type_val >](range: &BitRange) -> $type_val {
|
||||||
(1 << range.len) - 1
|
range.get_mask() as $type_val
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn [< clear_value_ $type_val >](dst: $type_val, range: &BitRange) -> $type_val {
|
pub const fn [< clear_value_ $type_val >](dst: $type_val, range: &BitRange) -> $type_val {
|
||||||
|
|
|
@ -184,11 +184,18 @@ pub fn input_to_vec(input: Input) -> Result<Vec<u8>, Error> {
|
||||||
|
|
||||||
pub fn read_file(file_path: &PathBuf) -> Result<Vec<u8>, Error> {
|
pub fn read_file(file_path: &PathBuf) -> Result<Vec<u8>, Error> {
|
||||||
match std::fs::read(file_path) {
|
match std::fs::read(file_path) {
|
||||||
Ok(data) => {
|
Ok(data) => Ok(data),
|
||||||
Ok(data)
|
Err(error) => create_file_read_error(file_path, error),
|
||||||
},
|
|
||||||
Err(error) => {
|
|
||||||
Err(Error::from_text(format!("Failed reading file {} with error: \"{}\"", file_path.display(), error)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_file_to_string(file_path: &PathBuf) -> Result<String, Error> {
|
||||||
|
match std::fs::read_to_string(file_path) {
|
||||||
|
Ok(string) => Ok(string),
|
||||||
|
Err(error) => create_file_read_error(file_path, error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_file_read_error<T>(file_path: &PathBuf, error: std::io::Error) -> Result<T, Error> {
|
||||||
|
Err(Error::from_text(format!("Failed reading file {} with error: \"{}\"", file_path.display(), error)))
|
||||||
}
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "wslpath"
|
||||||
|
version = "1.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = {version = "*", features = ["derive"]}
|
|
@ -0,0 +1,39 @@
|
||||||
|
pub fn convert(path: String) -> String {
|
||||||
|
replace_drive_letter(convert_slashes(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_slashes(path: String) -> String {
|
||||||
|
path.replace('\\', "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_drive_letter(mut path: String) -> String {
|
||||||
|
let has_drive_letter = {
|
||||||
|
let drive_letter = path.get(0..2);
|
||||||
|
|
||||||
|
if let Some(drive_letter) = drive_letter {
|
||||||
|
let starts_with_letter = drive_letter.chars().nth(0).unwrap_or('1').is_alphabetic();
|
||||||
|
let has_seperator = drive_letter.chars().nth(1).unwrap_or('x') == ':';
|
||||||
|
|
||||||
|
starts_with_letter && has_seperator
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if has_drive_letter {
|
||||||
|
path.replace_range(1..2, ""); // Removes :
|
||||||
|
if let Some(start_char) = path.get(0..1) { // Convert drive letter to lower case
|
||||||
|
path.replace_range(0..1, start_char.to_lowercase().as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.len() == 3 {
|
||||||
|
path.push('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
path.insert_str(0, "/mnt/");
|
||||||
|
}
|
||||||
|
|
||||||
|
path
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[clap(about = "A copy of the wslpath tool from wsl for faster execution", long_about = None)]
|
||||||
|
struct CommandLine {
|
||||||
|
#[clap(value_parser, help="The input path to convert to WSL")]
|
||||||
|
path_string: String
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match CommandLine::try_parse() {
|
||||||
|
Ok(cmd_line) => {
|
||||||
|
print!("{}", wslpath::convert(cmd_line.path_string));
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
eprintln!("{}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue