Merge pull request 'Support Overlays' (#2) from Overlay-The-Beginning_CDDrive into main

Reviewed-on: #2
This commit is contained in:
jaby 2023-04-22 09:38:31 +00:00
commit 4e70be31dc
64 changed files with 1666 additions and 1370 deletions

View File

@ -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();
}
}; };
} }

View File

@ -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);
} }
} }

View File

@ -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) { public:
this->start_adr = buffer_start_adr; CircularBuffer() = default;
this->read_idx = 0;
this->write_idx = 0;
}
T* allocate() { T* setup(T* buffer_start_adr, size_t elements) {
const auto new_idx = FastCircularBuffer::increment(this->write_idx, 1); this->start_adr = buffer_start_adr;
if(new_idx != this->read_idx) { this->end_adr = &buffer_start_adr[elements];
auto* dst = (this->start_adr + this->write_idx);
this->write_idx = new_idx; this->read_adr = this->start_adr;
return dst; 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");
}; };
} }

View File

@ -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__

View File

@ -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);
}; };

View File

@ -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__

View File

@ -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);
} }
} }

View 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__

View File

@ -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__

View File

@ -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);
} }
}; };

View File

@ -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;
} }
}; };

View File

@ -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__

View File

@ -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__

View File

@ -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;
} }
}; };

View File

@ -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__

View File

@ -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__

View File

@ -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);
} }
}; };
} }

View File

@ -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)
constexpr Raw read_raw() const { #define __declare_new_io_port_array(name, adr, size) \
return this->pod.read(); static inline auto& name = reinterpret_cast<name##_v(&)[size]>(*reinterpret_cast<name##_v*>(adr))
}
constexpr T read() const { // We need this construct to ensure the types end up being a POD - Inheritance doesn't qualify for a POD
return T{this->pod.read()}; #define __declare_io_type(name, type, ...) \
} template<template<typename> typename T> \
struct name##_io_base { \
constexpr Raw read(const BitRange<Raw>& range) const { typedef T<type>::UnderlyingValue UnderlyingValue; \
return VolatileBitMapPOD<T>::read().get_value(range); typedef name##_io_base Self; \
} \
T<type>::Value raw_value = 0; \
constexpr void write_raw(Raw value) { \
this->pod.write(value); __VA_ARGS__ \
} \
template<typename...ARGS> \
constexpr void write(const T& value) { static constexpr Self from(const ARGS&...args) { \
this->pod.write(static_cast<Raw>(value)); return Self().set_va(args...); \
} } \
\
constexpr void write(const BitRangeValue<Raw>& value) { constexpr Self& set(Bit bit) { \
VolatileBitMapPOD<T>::write(T{T::with(value)}); this->raw_value = bit::set(this->raw_value, bit); \
} return *this; \
}; } \
\
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__

View File

@ -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);
} }
} }

View File

@ -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__

View File

@ -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));
} }
} }

View File

@ -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

View File

@ -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__

View File

@ -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__

2
lib/ExportPath.mk Normal file
View File

@ -0,0 +1,2 @@
#Add the JabyEngine tools to path
export PATH := $(JABY_ENGINE_DIR)/bin/:$(PATH)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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__

View File

@ -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__

View File

@ -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

View File

@ -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__

View File

@ -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);
} }

View File

@ -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__

View File

@ -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;

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}
}
}

View File

@ -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);

View File

@ -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();

View File

@ -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;
} }
} }

View File

@ -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();
}
} }

View File

@ -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);
} }

View File

@ -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 constexpr auto XADPCM = Bit<uint8_t>(6);
static constexpr auto WholeSector = Bit<uint8_t>(5);
static constexpr auto DataSector = !WholeSector;
static constexpr auto UseXAFilter = Bit<uint8_t>(3);
static constexpr auto AudioPlayIRQ = Bit<uint8_t>(2);
static constexpr auto AutoPauseTrack = Bit<uint8_t>(1);
static constexpr auto CDDA = Bit<uint8_t>(0);
};
static constexpr auto DataSectorMode = Mode::with(Mode::DoubleSpeed, Mode::DataSector); static InterruptVerifierResult interrupt_verifier();
static void interrupt_handler(uint32_t);
static SectorBufferAllocator sector_allocator; static SectorBufferAllocator sector_allocator;
static uint16_t sectors_left; static uint32_t cur_lba;
static uint32_t dst_lba;
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 void pause_cd() {
CD_IO::PortIndex0::change_to();
Command::send<CD_IO::PortIndex0>(CD_IO::Command::Pause);
}
// 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);
}
} }
} }
} }

View File

@ -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;
}));
printf(">>> CD needs to load LBA: %i -> %i\n", cur_lba.lba, cur_lba.size_words); if(override_dst) {
dst_adr = reinterpret_cast<uint8_t*>(override_dst);
}
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;
CDFileProcessor::start_cur_job(); // 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();
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;
}
} }
} }

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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);
} }
} }
} }

View File

@ -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
} }

12
src/Library/src/run.cpp Normal file
View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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"
}, },
{ {

View File

@ -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 {

View File

@ -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

View File

@ -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>,
} }

View File

@ -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)?
}) })
} }

View File

@ -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 {

View File

@ -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}
} }
} }

View File

@ -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();

View File

@ -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 {

View File

@ -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)))
}

View File

@ -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"]}

View File

@ -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
}

View File

@ -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);
}
}
}