cpclib_asm/assembler/support/
cpr.rs1use cpclib_common::bitvec::vec::BitVec;
2use cpclib_common::riff::{RiffChunk, RiffCode};
3use cpclib_cpr::{CartridgeBank, Cpr};
4
5use super::banks::DecoratedPages;
6use crate::AssemblerError;
7use crate::page_info::PageInformation;
8use crate::support::banks::Bank;
9
10#[derive(Clone, Debug)]
14pub struct CprAssembler {
15 pages: DecoratedPages,
16 codes: Vec<(u8, String)>
17}
18
19impl Default for CprAssembler {
20 fn default() -> Self {
21 Self {
22 pages: DecoratedPages::default(),
23 codes: Vec::with_capacity(32)
24 }
25 }
26}
27
28impl TryInto<Cpr> for &CprAssembler {
29 type Error = AssemblerError;
30
31 fn try_into(self) -> Result<Cpr, AssemblerError> {
32 let mut chunks = Vec::with_capacity(self.codes.len());
33
34 for (code, page) in self.codes.iter().zip(self.pages.pages.iter()) {
35 let bank: Bank = page.try_into().map_err(|e: AssemblerError| {
36 AssemblerError::AssemblingError {
37 msg: format!("Error when building CPR bloc {}. {}", code.1, e)
38 }
39 })?;
40 let riff_code = RiffCode::from(code.1.as_str());
41 let riff = RiffChunk::new(riff_code, bank.into());
42 let chunk: CartridgeBank = riff.try_into().unwrap();
43 chunks.push(chunk);
44 }
45
46 chunks.sort_by_key(|bloc| bloc.code().clone());
47
48 Ok(chunks.into())
49 }
50}
51
52impl CprAssembler {
53 pub fn build_cpr(&self) -> Result<Cpr, AssemblerError> {
54 self.try_into()
55 }
56
57 pub fn selected_written_bytes(&self) -> Option<&BitVec> {
58 self.pages.selected_written_bytes()
59 }
60
61 pub fn selected_active_page_info_mut(&mut self) -> Option<&mut PageInformation> {
62 self.pages.selected_active_page_info_mut()
63 }
64
65 pub fn selected_active_page_info(&self) -> Option<&PageInformation> {
66 self.pages.selected_active_page_info()
67 }
68
69 pub fn page_infos(&self) -> impl Iterator<Item = &PageInformation> {
70 self.pages.page_infos()
71 }
72
73 pub fn select(&mut self, bank_number: u8) {
84 if let Some(idx) = self.code_to_index(bank_number) {
85 self.pages.selected_index = Some(idx);
86 }
87 else {
88 self.add_bank(bank_number);
89 self.pages.selected_index = Some(self.pages.pages.len() - 1);
90 }
91 }
92
93 fn add_bank(&mut self, bank_number: u8) {
94 let code = Self::number_to_code(bank_number);
95
96 assert!(self.code_to_index(bank_number).is_none()); self.pages.add_new_and_select();
98 self.codes.push((bank_number, code.into()));
99 }
100
101 fn number_to_code(bank_number: u8) -> &'static str {
102 CartridgeBank::code_for(bank_number)
103 }
104
105 fn code_to_index(&self, bank_number: u8) -> Option<usize> {
108 let code = Self::number_to_code(bank_number);
109 self.codes.iter().position(|c| c.1 == code)
110 }
111
112 pub fn selected_bloc(&self) -> Option<u8> {
113 self.pages.selected_index().map(|idx| self.codes[idx].0)
114 }
115
116 pub fn get_byte(&self, address: u16) -> Option<u8> {
117 self.pages.get_byte(address)
118 }
119
120 pub fn set_byte(&mut self, address: u16, byte: u8) -> Result<(), AssemblerError> {
122 if let Some(first) = self.pages.selected_active_page_info().unwrap().startadr {
125 let max = (first as u32 + 0x4000).min(0xFFFF) as u16;
126 if max > self.pages.selected_active_page_info().unwrap().output_limit {
127 dbg!(max, self.pages.selected_active_page_info());
128 todo!()
129 }
130 else {
131 self.pages
132 .selected_active_page_info_mut()
133 .unwrap()
134 .set_limit(max)?;
135 }
136 }
137
138 self.pages.set_byte(address, byte);
139 Ok(())
140 }
141
142 pub fn reset_written_bytes(&mut self) {
143 self.pages.reset_written_bytes();
144 }
145}
146
147impl CprAssembler {
148 pub fn is_empty(&self) -> bool {
149 self.pages.is_empty()
150 }
151}