cpclib_asm/assembler/support/
banks.rs

1use std::ops::{Deref, DerefMut};
2
3use cpclib_common::bitvec::vec::BitVec;
4
5use crate::page_info::PageInformation;
6use crate::{AssemblerError, MyDefault};
7
8pub(crate) type Bank = [u8; 0x4000];
9
10type Page = [u8; 0x1_0000];
11impl MyDefault for Page {
12    fn default() -> Page {
13        [0; 0x1_0000]
14    }
15}
16
17#[derive(Clone, Debug)]
18pub struct DecoratedPage((Page, PageInformation, BitVec));
19
20impl Deref for DecoratedPage {
21    type Target = (Page, PageInformation, BitVec);
22
23    fn deref(&self) -> &Self::Target {
24        &self.0
25    }
26}
27
28impl DerefMut for DecoratedPage {
29    fn deref_mut(&mut self) -> &mut Self::Target {
30        &mut self.0
31    }
32}
33
34impl Default for DecoratedPage {
35    fn default() -> Self {
36        Self((
37            Page::default(),
38            PageInformation::default(),
39            BitVec::repeat(false, 0x4000 * 4)
40        ))
41    }
42}
43
44impl DecoratedPage {
45    #[inline(always)]
46    fn page(&self) -> &Page {
47        &self.0.0
48    }
49
50    #[inline(always)]
51    fn page_information(&self) -> &PageInformation {
52        &self.0.1
53    }
54
55    #[inline(always)]
56    fn written_bytes(&self) -> &BitVec {
57        &self.0.2
58    }
59
60    /// Set the byte and store the written address
61    pub fn set_byte(&mut self, address: u16, byte: u8) {
62        self.0.0[address as usize] = byte;
63        self.0.2.set(address as _, true);
64    }
65
66    pub fn get_byte(&self, address: u16) -> u8 {
67        self.0.0[address as usize]
68    }
69}
70
71#[derive(Clone, Debug)]
72pub struct DecoratedPages {
73    pub(crate) pages: Vec<DecoratedPage>,
74    pub(crate) selected_index: Option<usize>
75}
76
77impl Default for DecoratedPages {
78    fn default() -> Self {
79        DecoratedPages {
80            pages: Vec::with_capacity(0),
81            selected_index: None
82        }
83    }
84}
85
86impl TryInto<Bank> for &DecoratedPage {
87    type Error = AssemblerError;
88
89    /// Copy the Page to the beginning of the bank, unless it is too huge
90    fn try_into(self) -> Result<Bank, Self::Error> {
91        let binary_bloc = self.binary_bloc();
92
93        if binary_bloc.len() > 0x4000 {
94            return Err(AssemblerError::AssemblingError {
95                msg: format!("0x{:X} > 0x4000", binary_bloc.len())
96            });
97        }
98
99        // get the appropriate bytes and copy them to the beginning
100        let mut bank: Bank = [0; 0x4000];
101        bank[..binary_bloc.len()].copy_from_slice(binary_bloc);
102        Ok(bank)
103    }
104}
105
106impl DecoratedPage {
107    /// REturns the memory bloc of written byte
108    pub fn binary_bloc(&self) -> &[u8] {
109        if let Some(start) = &self.page_information().startadr {
110            let stop = self.page_information().maxadr as usize;
111            &self.page()[(*start as usize)..=stop]
112        }
113        else {
114            &self.page()[..0]
115        }
116    }
117}
118
119impl DecoratedPages {
120    pub fn selected_index(&self) -> Option<usize> {
121        self.selected_index
122    }
123
124    pub fn selected_written_bytes(&self) -> Option<&BitVec> {
125        self.selected_index.as_ref().map(|&idx| &self.pages[idx].2)
126    }
127
128    pub fn selected_active_page_info_mut(&mut self) -> Option<&mut PageInformation> {
129        self.selected_index
130            .as_ref()
131            .map(|&idx| &mut self.pages[idx].1)
132    }
133
134    pub fn selected_active_page_info(&self) -> Option<&PageInformation> {
135        self.selected_index.as_ref().map(|&idx| &self.pages[idx].1)
136    }
137
138    pub fn page_infos(&self) -> impl Iterator<Item = &PageInformation> {
139        self.pages.iter().map(|d| &d.1)
140    }
141}
142
143impl DecoratedPages {
144    pub fn add_new_and_select(&mut self) {
145        self.selected_index = Some(self.pages.len());
146        self.pages.push(DecoratedPage::default());
147    }
148
149    pub fn select_next(&mut self) -> Result<(), AssemblerError> {
150        self.selected_index = self.selected_index.map(|v| v + 1).or(Some(0));
151
152        if *self.selected_index.as_ref().unwrap() >= self.pages.len() {
153            Err(AssemblerError::AssemblingError {
154                msg: "There were less banks in previous pass".to_owned()
155            })
156        }
157        else {
158            Ok(())
159        }
160    }
161
162    /// Write the byte in the page and save this information in written bytes
163    pub fn set_byte(&mut self, address: u16, byte: u8) {
164        if let Some(idx) = &self.selected_index {
165            self.pages[*idx].set_byte(address, byte);
166        }
167        else {
168            todo!()
169        }
170    }
171
172    pub fn get_byte(&self, address: u16) -> Option<u8> {
173        self.selected_index
174            .as_ref()
175            .map(|&idx| self.pages[idx].get_byte(address))
176    }
177
178    pub fn reset_written_bytes(&mut self) {
179        self.pages.iter_mut().for_each(|p| p.2.fill(false));
180    }
181}
182
183impl DecoratedPages {
184    pub fn is_empty(&self) -> bool {
185        self.pages.is_empty()
186    }
187}