cpclib_asm/assembler/support/
cpr.rsuse cpclib_common::bitvec::vec::BitVec;
use cpclib_common::riff::{RiffChunk, RiffCode};
use cpclib_cpr::{CartridgeBank, Cpr};
use super::banks::DecoratedPages;
use crate::page_info::PageInformation;
use crate::support::banks::Bank;
use crate::AssemblerError;
#[derive(Clone, Debug)]
pub struct CprAssembler {
pages: DecoratedPages,
codes: Vec<(u8, String)>
}
impl Default for CprAssembler {
fn default() -> Self {
Self {
pages: DecoratedPages::default(),
codes: Vec::with_capacity(32)
}
}
}
impl TryInto<Cpr> for &CprAssembler {
type Error = AssemblerError;
fn try_into(self) -> Result<Cpr, AssemblerError> {
let mut chunks = Vec::with_capacity(self.codes.len());
for (code, page) in self.codes.iter().zip(self.pages.pages.iter()) {
let bank: Bank = page.try_into().map_err(|e: AssemblerError| {
AssemblerError::AssemblingError {
msg: format!("Error when building CPR bloc {}. {}", code.1, e)
}
})?;
let riff_code = RiffCode::from(code.1.as_str());
let riff = RiffChunk::new(riff_code, bank.into());
let chunk: CartridgeBank = riff.try_into().unwrap();
chunks.push(chunk);
}
chunks.sort_by_key(|bloc| bloc.code().clone());
Ok(chunks.into())
}
}
impl CprAssembler {
pub fn build_cpr(&self) -> Result<Cpr, AssemblerError> {
self.try_into()
}
pub fn selected_written_bytes(&self) -> Option<&BitVec> {
self.pages.selected_written_bytes()
}
pub fn selected_active_page_info_mut(&mut self) -> Option<&mut PageInformation> {
self.pages.selected_active_page_info_mut()
}
pub fn selected_active_page_info(&self) -> Option<&PageInformation> {
self.pages.selected_active_page_info()
}
pub fn page_infos(&self) -> impl Iterator<Item = &PageInformation> {
self.pages.page_infos()
}
pub fn select(&mut self, bank_number: u8) {
if let Some(idx) = self.code_to_index(bank_number) {
self.pages.selected_index = Some(idx);
}
else {
self.add_bank(bank_number);
self.pages.selected_index = Some(self.pages.pages.len() - 1);
}
}
fn add_bank(&mut self, bank_number: u8) {
let code = Self::number_to_code(bank_number);
assert!(self.code_to_index(bank_number).is_none()); self.pages.add_new_and_select();
self.codes.push((bank_number, code.into()));
}
fn number_to_code(bank_number: u8) -> &'static str {
CartridgeBank::code_for(bank_number)
}
fn code_to_index(&self, bank_number: u8) -> Option<usize> {
let code = Self::number_to_code(bank_number);
self.codes.iter().position(|c| c.1 == code)
}
pub fn selected_bloc(&self) -> Option<u8> {
self.pages.selected_index().map(|idx| self.codes[idx].0)
}
pub fn get_byte(&self, address: u16) -> Option<u8> {
self.pages.get_byte(address)
}
pub fn set_byte(&mut self, address: u16, byte: u8) -> Result<(), AssemblerError> {
if let Some(first) = self.pages.selected_active_page_info().unwrap().startadr {
let max = (first as u32 + 0x4000).min(0xFFFF) as u16;
if max > self.pages.selected_active_page_info().unwrap().output_limit {
dbg!(max, self.pages.selected_active_page_info());
todo!()
}
else {
self.pages
.selected_active_page_info_mut()
.unwrap()
.set_limit(max)?;
}
}
self.pages.set_byte(address, byte);
Ok(())
}
pub fn reset_written_bytes(&mut self) {
self.pages.reset_written_bytes();
}
}
impl CprAssembler {
pub fn is_empty(&self) -> bool {
self.pages.is_empty()
}
}