pr 00.1 optimize imports and created hinfra
This commit is contained in:
parent
567ab21709
commit
60384bf720
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -2241,6 +2241,14 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometeu-hinfra"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prometeu-lsp"
|
||||
version = "0.1.0"
|
||||
|
||||
@ -8,6 +8,7 @@ members = [
|
||||
"crates/prometeu-compiler",
|
||||
"crates/prometeu-analysis",
|
||||
"crates/prometeu-lsp",
|
||||
"crates/prometeu-hinfra"
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ mod log_source;
|
||||
mod log_event;
|
||||
mod log_service;
|
||||
|
||||
pub use log_level::LogLevel;
|
||||
pub use log_source::LogSource;
|
||||
pub use log_event::LogEvent;
|
||||
pub use log_level::LogLevel;
|
||||
pub use log_service::LogService;
|
||||
pub use log_source::LogSource;
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
use crate::abi::SourceSpan;
|
||||
use crate::opcode::OpCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use crate::building::output::{CompiledModule};
|
||||
use crate::building::output::CompiledModule;
|
||||
use crate::building::plan::BuildStep;
|
||||
use prometeu_bytecode::opcode::OpCode;
|
||||
use prometeu_bytecode::{ConstantPoolEntry, DebugInfo};
|
||||
use prometeu_core::virtual_machine::{ProgramImage, Value};
|
||||
use std::collections::{HashMap};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum LinkError {
|
||||
@ -276,14 +276,14 @@ impl Linker {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::BTreeMap;
|
||||
use super::*;
|
||||
use crate::building::output::{ExportKey, ExportMetadata, ImportKey, ImportMetadata};
|
||||
use crate::semantics::export_surface::ExportSurfaceKind;
|
||||
use crate::building::plan::BuildTarget;
|
||||
use crate::deps::resolver::ProjectId;
|
||||
use crate::semantics::export_surface::ExportSurfaceKind;
|
||||
use prometeu_bytecode::opcode::OpCode;
|
||||
use prometeu_bytecode::FunctionMeta;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
fn test_link_root_and_lib() {
|
||||
|
||||
@ -12,8 +12,8 @@ use crate::frontends::pbs::resolver::{ModuleProvider, Resolver};
|
||||
use crate::frontends::pbs::symbols::{ModuleSymbols, Namespace, Symbol, SymbolKind, Visibility};
|
||||
use crate::frontends::pbs::typecheck::TypeChecker;
|
||||
use crate::frontends::pbs::types::PbsType;
|
||||
use crate::semantics::export_surface::ExportSurfaceKind;
|
||||
use crate::lowering::core_to_vm;
|
||||
use crate::semantics::export_surface::ExportSurfaceKind;
|
||||
use prometeu_bytecode::{ConstantPoolEntry, DebugInfo, FunctionMeta};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::common::spans::Span;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
|
||||
use crate::backend;
|
||||
use crate::common::config::ProjectConfig;
|
||||
use crate::common::symbols::{DebugSymbol, RawSymbol, SymbolsFile, ProjectSymbols};
|
||||
use crate::common::files::FileManager;
|
||||
use crate::common::spans::Span;
|
||||
use crate::common::symbols::{DebugSymbol, ProjectSymbols, RawSymbol, SymbolsFile};
|
||||
use anyhow::Result;
|
||||
use prometeu_bytecode::BytecodeModule;
|
||||
use std::path::Path;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use super::ids::ValueId;
|
||||
use super::instr::{InstrKind};
|
||||
use super::instr::InstrKind;
|
||||
use super::program::Program;
|
||||
use super::terminator::Terminator;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::path::PathBuf;
|
||||
use tempfile::tempdir;
|
||||
use prometeu_compiler::building::output::CompiledModule;
|
||||
use prometeu_compiler::building::output::{compile_project, CompileError, ExportKey, ExportMetadata};
|
||||
use prometeu_compiler::building::plan::{BuildStep, BuildTarget};
|
||||
use prometeu_compiler::common::files::FileManager;
|
||||
use prometeu_compiler::deps::resolver::ProjectId;
|
||||
use prometeu_compiler::semantics::export_surface::ExportSurfaceKind;
|
||||
use prometeu_compiler::building::output::CompiledModule;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::path::PathBuf;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use std::fs;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use prometeu_compiler::compiler::compile;
|
||||
use prometeu_core::hardware::{AssetManager, Audio, Gfx, HardwareBridge, MemoryBanks, Pad, Touch};
|
||||
use prometeu_core::virtual_machine::{HostReturn, LogicalFrameEndingReason, NativeInterface, Value, VirtualMachine, VmFault, HostContext};
|
||||
use prometeu_core::virtual_machine::{HostContext, HostReturn, LogicalFrameEndingReason, NativeInterface, Value, VirtualMachine, VmFault};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
@ -101,7 +101,6 @@ pub enum DebugEvent {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::virtual_machine::Value;
|
||||
|
||||
#[test]
|
||||
|
||||
@ -24,9 +24,9 @@ mod prometeu_hub;
|
||||
|
||||
// Facade/reexports for ABI modules (temporary during PR-00.x)
|
||||
pub use prometeu_abi as abi;
|
||||
pub use prometeu_abi::model;
|
||||
pub use prometeu_abi::log;
|
||||
pub use prometeu_abi::telemetry;
|
||||
pub use prometeu_abi::debugger_protocol;
|
||||
pub use prometeu_abi::log;
|
||||
pub use prometeu_abi::model;
|
||||
pub use prometeu_abi::telemetry;
|
||||
|
||||
pub use hardware::hardware::Hardware;
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
use crate::log::LogLevel;
|
||||
use crate::log::LogSource;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LogEvent {
|
||||
pub seq: u64,
|
||||
pub ts_ms: u64,
|
||||
pub frame: u64,
|
||||
pub level: LogLevel,
|
||||
pub source: LogSource,
|
||||
pub tag: u16,
|
||||
pub msg: String,
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LogLevel {
|
||||
Trace,
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
use crate::log::{LogEvent, LogLevel, LogSource};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub struct LogService {
|
||||
events: VecDeque<LogEvent>,
|
||||
capacity: usize,
|
||||
next_seq: u64,
|
||||
}
|
||||
|
||||
impl LogService {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
Self {
|
||||
events: VecDeque::with_capacity(capacity),
|
||||
capacity,
|
||||
next_seq: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log(&mut self, ts_ms: u64, frame: u64, level: LogLevel, source: LogSource, tag: u16, msg: String) {
|
||||
if self.events.len() >= self.capacity {
|
||||
self.events.pop_front();
|
||||
}
|
||||
self.events.push_back(LogEvent {
|
||||
seq: self.next_seq,
|
||||
ts_ms,
|
||||
frame,
|
||||
level,
|
||||
source,
|
||||
tag,
|
||||
msg,
|
||||
});
|
||||
self.next_seq += 1;
|
||||
}
|
||||
|
||||
pub fn get_recent(&self, n: usize) -> Vec<LogEvent> {
|
||||
self.events.iter().rev().take(n).cloned().collect::<Vec<_>>().into_iter().rev().collect()
|
||||
}
|
||||
|
||||
pub fn get_after(&self, seq: u64) -> Vec<LogEvent> {
|
||||
self.events.iter().filter(|e| e.seq > seq).cloned().collect()
|
||||
}
|
||||
|
||||
pub fn last_seq(&self) -> Option<u64> {
|
||||
self.events.back().map(|e| e.seq)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_ring_buffer_capacity() {
|
||||
let mut service = LogService::new(3);
|
||||
service.log(100, 1, LogLevel::Info, LogSource::Pos, 0, "Log 1".to_string());
|
||||
service.log(110, 1, LogLevel::Info, LogSource::Pos, 0, "Log 2".to_string());
|
||||
service.log(120, 1, LogLevel::Info, LogSource::Pos, 0, "Log 3".to_string());
|
||||
|
||||
assert_eq!(service.events.len(), 3);
|
||||
assert_eq!(service.events[0].msg, "Log 1");
|
||||
|
||||
service.log(130, 1, LogLevel::Info, LogSource::Pos, 0, "Log 4".to_string());
|
||||
assert_eq!(service.events.len(), 3);
|
||||
assert_eq!(service.events[0].msg, "Log 2");
|
||||
assert_eq!(service.events[2].msg, "Log 4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_recent() {
|
||||
let mut service = LogService::new(10);
|
||||
for i in 0..5 {
|
||||
service.log(i as u64, 1, LogLevel::Info, LogSource::Pos, 0, format!("Log {}", i));
|
||||
}
|
||||
|
||||
let recent = service.get_recent(2);
|
||||
assert_eq!(recent.len(), 2);
|
||||
assert_eq!(recent[0].msg, "Log 3");
|
||||
assert_eq!(recent[1].msg, "Log 4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_after() {
|
||||
let mut service = LogService::new(10);
|
||||
for i in 0..5 {
|
||||
service.log(i as u64, 1, LogLevel::Info, LogSource::Pos, 0, format!("Log {}", i));
|
||||
}
|
||||
|
||||
let after = service.get_after(2); // seqs are 0, 1, 2, 3, 4. Should return 3 and 4.
|
||||
assert_eq!(after.len(), 2);
|
||||
assert_eq!(after[0].msg, "Log 3");
|
||||
assert_eq!(after[1].msg, "Log 4");
|
||||
}
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LogSource {
|
||||
Pos,
|
||||
Hub,
|
||||
Vm,
|
||||
Fs,
|
||||
App { app_id: u32 },
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
mod log_level;
|
||||
mod log_source;
|
||||
mod log_event;
|
||||
mod log_service;
|
||||
|
||||
pub use log_event::LogEvent;
|
||||
pub use log_level::LogLevel;
|
||||
pub use log_service::LogService;
|
||||
pub use log_source::LogSource;
|
||||
@ -1,80 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type HandleId = u32;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BankType {
|
||||
TILES,
|
||||
SOUNDS,
|
||||
// TILEMAPS,
|
||||
// BLOBS,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct AssetEntry {
|
||||
pub asset_id: u32,
|
||||
pub asset_name: String,
|
||||
pub bank_type: BankType,
|
||||
pub offset: u64,
|
||||
pub size: u64,
|
||||
pub decoded_size: u64,
|
||||
pub codec: String, // e.g., "RAW"
|
||||
pub metadata: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct PreloadEntry {
|
||||
pub asset_name: String,
|
||||
pub slot: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum LoadStatus {
|
||||
PENDING,
|
||||
LOADING,
|
||||
READY,
|
||||
COMMITTED,
|
||||
CANCELED,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BankStats {
|
||||
pub total_bytes: usize,
|
||||
pub used_bytes: usize,
|
||||
pub free_bytes: usize,
|
||||
pub inflight_bytes: usize,
|
||||
pub slot_count: usize,
|
||||
pub slots_occupied: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SlotStats {
|
||||
pub asset_id: Option<u32>,
|
||||
pub asset_name: Option<String>,
|
||||
pub generation: u32,
|
||||
pub resident_bytes: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct SlotRef {
|
||||
pub asset_type: BankType,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl SlotRef {
|
||||
pub fn gfx(index: usize) -> Self {
|
||||
Self {
|
||||
asset_type: BankType::TILES,
|
||||
index,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn audio(index: usize) -> Self {
|
||||
Self {
|
||||
asset_type: BankType::SOUNDS,
|
||||
index,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u32)]
|
||||
pub enum ButtonId {
|
||||
Up = 0,
|
||||
Down = 1,
|
||||
Left = 2,
|
||||
Right = 3,
|
||||
A = 4,
|
||||
B = 5,
|
||||
X = 6,
|
||||
Y = 7,
|
||||
L = 8,
|
||||
R = 9,
|
||||
Start = 10,
|
||||
Select = 11,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, Debug)]
|
||||
pub struct Button {
|
||||
pub pressed: bool,
|
||||
pub released: bool,
|
||||
pub down: bool,
|
||||
pub hold_frames: u32,
|
||||
}
|
||||
|
||||
impl Button {
|
||||
pub fn begin_frame(&mut self, is_down_now: bool) {
|
||||
let was_down = self.down;
|
||||
self.down = is_down_now.clone();
|
||||
|
||||
self.pressed = !was_down && self.down;
|
||||
self.released = was_down && !self.down;
|
||||
|
||||
if self.down {
|
||||
self.hold_frames = self.hold_frames.saturating_add(1);
|
||||
} else {
|
||||
self.hold_frames = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
use crate::model::asset::{AssetEntry, PreloadEntry};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub enum AppMode {
|
||||
Game,
|
||||
System,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Cartridge {
|
||||
pub app_id: u32,
|
||||
pub title: String,
|
||||
pub app_version: String,
|
||||
pub app_mode: AppMode,
|
||||
pub entrypoint: String,
|
||||
pub program: Vec<u8>,
|
||||
pub assets: Vec<u8>,
|
||||
pub asset_table: Vec<AssetEntry>,
|
||||
pub preload: Vec<PreloadEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct CartridgeDTO {
|
||||
pub app_id: u32,
|
||||
pub title: String,
|
||||
pub app_version: String,
|
||||
pub app_mode: AppMode,
|
||||
pub entrypoint: String,
|
||||
pub program: Vec<u8>,
|
||||
pub assets: Vec<u8>,
|
||||
#[serde(default)]
|
||||
pub asset_table: Vec<AssetEntry>,
|
||||
#[serde(default)]
|
||||
pub preload: Vec<PreloadEntry>,
|
||||
}
|
||||
|
||||
impl From<CartridgeDTO> for Cartridge {
|
||||
fn from(dto: CartridgeDTO) -> Self {
|
||||
Self {
|
||||
app_id: dto.app_id,
|
||||
title: dto.title,
|
||||
app_version: dto.app_version,
|
||||
app_mode: dto.app_mode,
|
||||
entrypoint: dto.entrypoint,
|
||||
program: dto.program,
|
||||
assets: dto.assets,
|
||||
asset_table: dto.asset_table,
|
||||
preload: dto.preload,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CartridgeError {
|
||||
NotFound,
|
||||
InvalidFormat,
|
||||
InvalidManifest,
|
||||
UnsupportedVersion,
|
||||
MissingProgram,
|
||||
IoError,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CartridgeManifest {
|
||||
pub magic: String,
|
||||
pub cartridge_version: u32,
|
||||
pub app_id: u32,
|
||||
pub title: String,
|
||||
pub app_version: String,
|
||||
pub app_mode: AppMode,
|
||||
pub entrypoint: String,
|
||||
#[serde(default)]
|
||||
pub asset_table: Vec<AssetEntry>,
|
||||
#[serde(default)]
|
||||
pub preload: Vec<PreloadEntry>,
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
use crate::model::cartridge::{Cartridge, CartridgeDTO, CartridgeError, CartridgeManifest};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
pub struct CartridgeLoader;
|
||||
|
||||
impl CartridgeLoader {
|
||||
pub fn load(path: impl AsRef<Path>) -> Result<Cartridge, CartridgeError> {
|
||||
let path = path.as_ref();
|
||||
if !path.exists() {
|
||||
return Err(CartridgeError::NotFound);
|
||||
}
|
||||
|
||||
if path.is_dir() {
|
||||
DirectoryCartridgeLoader::load(path)
|
||||
} else if path.extension().is_some_and(|ext| ext == "pmc") {
|
||||
PackedCartridgeLoader::load(path)
|
||||
} else {
|
||||
Err(CartridgeError::InvalidFormat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DirectoryCartridgeLoader;
|
||||
|
||||
impl DirectoryCartridgeLoader {
|
||||
pub fn load(path: &Path) -> Result<Cartridge, CartridgeError> {
|
||||
let manifest_path = path.join("manifest.json");
|
||||
if !manifest_path.exists() {
|
||||
return Err(CartridgeError::InvalidManifest);
|
||||
}
|
||||
|
||||
let manifest_content = fs::read_to_string(manifest_path).map_err(|_| CartridgeError::IoError)?;
|
||||
let manifest: CartridgeManifest = serde_json::from_str(&manifest_content).map_err(|_| CartridgeError::InvalidManifest)?;
|
||||
|
||||
// Additional validation as per requirements
|
||||
if manifest.magic != "PMTU" {
|
||||
return Err(CartridgeError::InvalidManifest);
|
||||
}
|
||||
if manifest.cartridge_version != 1 {
|
||||
return Err(CartridgeError::UnsupportedVersion);
|
||||
}
|
||||
|
||||
let program_path = path.join("program.pbc");
|
||||
if !program_path.exists() {
|
||||
return Err(CartridgeError::MissingProgram);
|
||||
}
|
||||
|
||||
let program = fs::read(program_path).map_err(|_| CartridgeError::IoError)?;
|
||||
|
||||
let assets_pa_path = path.join("assets.pa");
|
||||
let assets = if assets_pa_path.exists() {
|
||||
fs::read(assets_pa_path).map_err(|_| CartridgeError::IoError)?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let dto = CartridgeDTO {
|
||||
app_id: manifest.app_id,
|
||||
title: manifest.title,
|
||||
app_version: manifest.app_version,
|
||||
app_mode: manifest.app_mode,
|
||||
entrypoint: manifest.entrypoint,
|
||||
program,
|
||||
assets,
|
||||
asset_table: manifest.asset_table,
|
||||
preload: manifest.preload,
|
||||
};
|
||||
|
||||
Ok(Cartridge::from(dto))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PackedCartridgeLoader;
|
||||
|
||||
impl PackedCartridgeLoader {
|
||||
pub fn load(_path: &Path) -> Result<Cartridge, CartridgeError> {
|
||||
Err(CartridgeError::InvalidFormat)
|
||||
}
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
/// Represents a 16-bit color in the RGB565 format.
|
||||
///
|
||||
/// The RGB565 format is a common high-color representation for embedded systems:
|
||||
/// - **Red**: 5 bits (0..31)
|
||||
/// - **Green**: 6 bits (0..63)
|
||||
/// - **Blue**: 5 bits (0..31)
|
||||
///
|
||||
/// Prometeu does not have a hardware alpha channel. Transparency is achieved
|
||||
/// by using a specific color key (Magenta / 0xF81F) which the GFX engine
|
||||
/// skips during rendering.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct Color(pub u16);
|
||||
|
||||
impl Color {
|
||||
pub const BLACK: Self = Self::rgb(0, 0, 0); // 0x0000
|
||||
pub const WHITE: Self = Self::rgb(255, 255, 255); // 0xFFFF
|
||||
pub const RED: Self = Self::rgb(255, 0, 0); // 0xF800
|
||||
pub const GREEN: Self = Self::rgb(0, 255, 0); // 0x07E0
|
||||
pub const BLUE: Self = Self::rgb(0, 0, 255); // 0x001F
|
||||
pub const YELLOW: Self = Self::rgb(255, 255, 0); // 0xFFE0
|
||||
pub const ORANGE: Self = Self::rgb(255, 128, 0);
|
||||
pub const INDIGO: Self = Self::rgb(75, 0, 130);
|
||||
pub const GRAY: Self = Self::rgb(128, 128, 128);
|
||||
pub const CYAN: Self = Self::rgb(0, 255, 255); // 0x07FF
|
||||
pub const MAGENTA: Self = Self::rgb(255, 0, 255); // 0xF81F
|
||||
pub const COLOR_KEY: Self = Self::MAGENTA;
|
||||
pub const TRANSPARENT: Self = Self::MAGENTA;
|
||||
|
||||
/// Extracts channels in the native RGB565 range:
|
||||
/// R: 0..31, G: 0..63, B: 0..31
|
||||
#[inline(always)]
|
||||
pub const fn unpack_to_native(px: u16) -> (u8, u8, u8) {
|
||||
let r = ((px >> 11) & 0x1F) as u8;
|
||||
let g = ((px >> 5) & 0x3F) as u8;
|
||||
let b = (px & 0x1F) as u8;
|
||||
(r, g, b)
|
||||
}
|
||||
|
||||
/// Packs channels from the native RGB565 range into a pixel:
|
||||
/// R: 0..31, G: 0..63, B: 0..31
|
||||
#[inline(always)]
|
||||
pub const fn pack_from_native(r: u8, g: u8, b: u8) -> u16 {
|
||||
((r as u16 & 0x1F) << 11) | ((g as u16 & 0x3F) << 5) | (b as u16 & 0x1F)
|
||||
}
|
||||
|
||||
/// Creates an RGB565 color from 8-bit components (0..255).
|
||||
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
let r5 = (r as u16 >> 3) & 0x1F;
|
||||
let g6 = (g as u16 >> 2) & 0x3F;
|
||||
let b5 = (b as u16 >> 3) & 0x1F;
|
||||
|
||||
Self((r5 << 11) | (g6 << 5) | b5)
|
||||
}
|
||||
|
||||
pub const fn gray_scale(c: u8) -> Self {
|
||||
Self::rgb(c, c, c)
|
||||
}
|
||||
|
||||
pub const fn from_raw(raw: u16) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
pub const fn raw(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub const fn hex(self) -> i32 {
|
||||
let (r5, g6, b5) = Self::unpack_to_native(self.0);
|
||||
let r8 = ((r5 as u32) << 3) | ((r5 as u32) >> 2);
|
||||
let g8 = ((g6 as u32) << 2) | ((g6 as u32) >> 4);
|
||||
let b8 = ((b5 as u32) << 3) | ((b5 as u32) >> 2);
|
||||
let hex = r8 << 16 | g8 << 8 | b8;
|
||||
hex as i32
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
mod asset;
|
||||
mod color;
|
||||
mod button;
|
||||
mod tile;
|
||||
mod tile_layer;
|
||||
mod tile_bank;
|
||||
mod sound_bank;
|
||||
mod sprite;
|
||||
mod sample;
|
||||
mod cartridge;
|
||||
mod cartridge_loader;
|
||||
mod window;
|
||||
|
||||
pub use asset::{AssetEntry, BankStats, BankType, HandleId, LoadStatus, PreloadEntry, SlotRef, SlotStats};
|
||||
pub use button::{Button, ButtonId};
|
||||
pub use cartridge::{AppMode, Cartridge, CartridgeDTO, CartridgeError};
|
||||
pub use cartridge_loader::{CartridgeLoader, DirectoryCartridgeLoader, PackedCartridgeLoader};
|
||||
pub use color::Color;
|
||||
pub use sample::Sample;
|
||||
pub use sound_bank::SoundBank;
|
||||
pub use sprite::Sprite;
|
||||
pub use tile::Tile;
|
||||
pub use tile_bank::{TileBank, TileSize};
|
||||
pub use tile_layer::{HudTileLayer, ScrollableTileLayer, TileMap};
|
||||
pub use window::{Rect, Window, WindowId};
|
||||
@ -1,27 +0,0 @@
|
||||
pub struct Sample {
|
||||
pub sample_rate: u32,
|
||||
pub data: Vec<i16>,
|
||||
pub loop_start: Option<u32>,
|
||||
pub loop_end: Option<u32>,
|
||||
}
|
||||
|
||||
impl Sample {
|
||||
pub fn new(sample_rate: u32, data: Vec<i16>) -> Self {
|
||||
Self {
|
||||
sample_rate,
|
||||
data,
|
||||
loop_start: None,
|
||||
loop_end: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_loop(mut self, start: u32, end: u32) -> Self {
|
||||
self.loop_start = Some(start);
|
||||
self.loop_end = Some(end);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn frames_len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
use crate::model::Sample;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A container for audio assets.
|
||||
///
|
||||
/// A SoundBank stores multiple audio samples that can be played by the
|
||||
/// audio subsystem.
|
||||
pub struct SoundBank {
|
||||
pub samples: Vec<Arc<Sample>>,
|
||||
}
|
||||
|
||||
impl SoundBank {
|
||||
pub fn new(samples: Vec<Arc<Sample>>) -> Self {
|
||||
Self { samples }
|
||||
}
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
use crate::model::Tile;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Sprite {
|
||||
pub tile: Tile,
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub bank_id: u8,
|
||||
pub active: bool,
|
||||
pub flip_x: bool,
|
||||
pub flip_y: bool,
|
||||
pub priority: u8,
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Tile {
|
||||
pub id: u16,
|
||||
pub flip_x: bool,
|
||||
pub flip_y: bool,
|
||||
pub palette_id: u8,
|
||||
}
|
||||
@ -1,75 +0,0 @@
|
||||
use crate::model::Color;
|
||||
|
||||
/// Standard sizes for square tiles.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum TileSize {
|
||||
/// 8x8 pixels.
|
||||
Size8 = 8,
|
||||
/// 16x16 pixels.
|
||||
Size16 = 16,
|
||||
/// 32x32 pixels.
|
||||
Size32 = 32,
|
||||
}
|
||||
|
||||
/// A container for graphical assets.
|
||||
///
|
||||
/// A TileBank stores both the raw pixel data (as palette indices) and the
|
||||
/// color palettes themselves. This encapsulates all the information needed
|
||||
/// to render a set of tiles.
|
||||
pub struct TileBank {
|
||||
/// Dimension of each individual tile in the bank.
|
||||
pub tile_size: TileSize,
|
||||
/// Width of the full bank sheet in pixels.
|
||||
pub width: usize,
|
||||
/// Height of the full bank sheet in pixels.
|
||||
pub height: usize,
|
||||
|
||||
/// Pixel data stored as 4-bit indices (packed into 8-bit values).
|
||||
/// Index 0 is always reserved for transparency.
|
||||
pub pixel_indices: Vec<u8>,
|
||||
/// Table of 64 palettes, each containing 16 RGB565 colors, total of 1024 colors for a bank.
|
||||
pub palettes: [[Color; 16]; 64],
|
||||
}
|
||||
|
||||
impl TileBank {
|
||||
/// Creates an empty tile bank with the specified dimensions.
|
||||
pub fn new(tile_size: TileSize, width: usize, height: usize) -> Self {
|
||||
Self {
|
||||
tile_size,
|
||||
width,
|
||||
height,
|
||||
pixel_indices: vec![0; width * height], // Index 0 = Transparent
|
||||
palettes: [[Color::BLACK; 16]; 64],
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a global tile ID and local pixel coordinates to a palette index.
|
||||
/// tile_id: the tile index in the bank
|
||||
/// local_x, local_y: the pixel position inside the tile (0 to tile_size-1)
|
||||
pub fn get_pixel_index(&self, tile_id: u16, local_x: usize, local_y: usize) -> u8 {
|
||||
let size = self.tile_size as usize;
|
||||
let tiles_per_row = self.width / size;
|
||||
let tile_x = (tile_id as usize % tiles_per_row) * size;
|
||||
let tile_y = (tile_id as usize / tiles_per_row) * size;
|
||||
|
||||
let pixel_x = tile_x + local_x;
|
||||
let pixel_y = tile_y + local_y;
|
||||
|
||||
if pixel_x < self.width && pixel_y < self.height {
|
||||
self.pixel_indices[pixel_y * self.width + pixel_x]
|
||||
} else {
|
||||
0 // Default to transparent if out of bounds
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps a 4-bit index to a real RGB565 Color using the specified palette.
|
||||
pub fn resolve_color(&self, palette_id: u8, pixel_index: u8) -> Color {
|
||||
// Hardware Rule: Index 0 is always transparent.
|
||||
// We use Magenta as the 'transparent' signal color during composition.
|
||||
if pixel_index == 0 {
|
||||
return Color::COLOR_KEY;
|
||||
}
|
||||
|
||||
self.palettes[palette_id as usize][pixel_index as usize]
|
||||
}
|
||||
}
|
||||
@ -1,109 +0,0 @@
|
||||
use crate::model::tile_bank::TileSize;
|
||||
use crate::model::Tile;
|
||||
use crate::model::TileSize::Size8;
|
||||
|
||||
pub struct TileMap {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub tiles: Vec<Tile>,
|
||||
}
|
||||
|
||||
impl TileMap {
|
||||
fn create(width: usize, height: usize) -> Self {
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
tiles: vec![Tile::default(); width * height],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_tile(&mut self, x: usize, y: usize, tile: Tile) {
|
||||
if x < self.width && y < self.height {
|
||||
self.tiles[y * self.width + x] = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct TileLayer {
|
||||
pub bank_id: u8,
|
||||
pub tile_size: TileSize,
|
||||
pub map: TileMap,
|
||||
}
|
||||
|
||||
impl TileLayer {
|
||||
fn create(width: usize, height: usize, tile_size: TileSize) -> Self {
|
||||
Self {
|
||||
bank_id: 0,
|
||||
tile_size,
|
||||
map: TileMap::create(width, height),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for TileLayer {
|
||||
type Target = TileMap;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.map
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for TileLayer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.map
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ScrollableTileLayer {
|
||||
pub layer: TileLayer,
|
||||
pub scroll_x: i32,
|
||||
pub scroll_y: i32,
|
||||
}
|
||||
|
||||
impl ScrollableTileLayer {
|
||||
pub fn new(width: usize, height: usize, tile_size: TileSize) -> Self {
|
||||
Self {
|
||||
layer: TileLayer::create(width, height, tile_size),
|
||||
scroll_x: 0,
|
||||
scroll_y: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for ScrollableTileLayer {
|
||||
type Target = TileLayer;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.layer
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for ScrollableTileLayer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.layer
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HudTileLayer {
|
||||
pub layer: TileLayer,
|
||||
}
|
||||
|
||||
impl HudTileLayer {
|
||||
pub fn new(width: usize, height: usize) -> Self {
|
||||
Self {
|
||||
layer: TileLayer::create(width, height, Size8),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for HudTileLayer {
|
||||
type Target = TileLayer;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.layer
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for HudTileLayer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.layer
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
use crate::model::Color;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Rect {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub w: i32,
|
||||
pub h: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct WindowId(pub u32);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Window {
|
||||
pub id: WindowId,
|
||||
pub viewport: Rect,
|
||||
pub has_focus: bool,
|
||||
pub title: String,
|
||||
pub color: Color,
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
use crate::fs::{FsBackend, FsState, VirtualFS};
|
||||
use crate::abi::syscalls::Syscall;
|
||||
use crate::fs::{FsBackend, FsState, VirtualFS};
|
||||
use crate::hardware::{HardwareBridge, InputSignals};
|
||||
use crate::log::{LogLevel, LogService, LogSource};
|
||||
use crate::model::{BankType, Cartridge, Color};
|
||||
use crate::prometeu_os::NativeInterface;
|
||||
use crate::telemetry::{CertificationConfig, Certifier, TelemetryFrame};
|
||||
use crate::virtual_machine::{expect_bool, expect_int, HostReturn, SyscallId, Value, VirtualMachine, VmFault, HostContext};
|
||||
use crate::virtual_machine::{expect_bool, expect_int, HostContext, HostReturn, SyscallId, Value, VirtualMachine, VmFault};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
|
||||
|
||||
@ -10,9 +10,9 @@ pub mod verifier;
|
||||
|
||||
pub use host_context::{HostContext, HostContextProvider};
|
||||
pub use program::ProgramImage;
|
||||
pub use prometeu_abi::virtual_machine::Value;
|
||||
pub use prometeu_bytecode::abi::TrapInfo;
|
||||
pub use prometeu_bytecode::opcode::OpCode;
|
||||
pub use prometeu_abi::virtual_machine::Value;
|
||||
pub use verifier::VerifierError;
|
||||
pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine};
|
||||
|
||||
|
||||
@ -107,8 +107,6 @@ impl Value {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_value_equality() {
|
||||
assert_eq!(Value::Int32(10), Value::Int32(10));
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use crate::abi::syscalls::Syscall;
|
||||
use crate::virtual_machine::bytecode::decoder::{decode_at, DecodeError};
|
||||
use prometeu_bytecode::opcode::OpCode;
|
||||
use prometeu_bytecode::FunctionMeta;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use crate::abi::syscalls::Syscall;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum VerifierError {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::virtual_machine::call_frame::CallFrame;
|
||||
use crate::virtual_machine::scope_frame::ScopeFrame;
|
||||
use crate::virtual_machine::Value;
|
||||
use crate::virtual_machine::{NativeInterface, ProgramImage, VmInitError, HostContext};
|
||||
use crate::virtual_machine::{HostContext, NativeInterface, ProgramImage, VmInitError};
|
||||
use prometeu_bytecode::abi::{TrapInfo, TRAP_BAD_RET_SLOTS, TRAP_DIV_ZERO, TRAP_INVALID_FUNC, TRAP_OOB, TRAP_TYPE};
|
||||
use prometeu_bytecode::opcode::OpCode;
|
||||
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
use prometeu_core::hardware::HardwareBridge;
|
||||
use prometeu_core::virtual_machine::HostReturn;
|
||||
use prometeu_core::virtual_machine::NativeInterface;
|
||||
use prometeu_core::virtual_machine::Value;
|
||||
use prometeu_core::virtual_machine::{LogicalFrameEndingReason, VirtualMachine, HostContext};
|
||||
use prometeu_core::virtual_machine::{HostContext, LogicalFrameEndingReason, VirtualMachine};
|
||||
use prometeu_core::Hardware;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
9
crates/prometeu-hinfra/Cargo.toml
Normal file
9
crates/prometeu-hinfra/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "prometeu-hinfra"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_json = "1.0.149"
|
||||
0
crates/prometeu-hinfra/src/lib.rs
Normal file
0
crates/prometeu-hinfra/src/lib.rs
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user