use super::libc;
use crate::poke;
use alloc::{string::String, vec::Vec};
use core::mem::MaybeUninit;
pub const MAX_28_BIT_ADDRESS: u32 = 0xFFFFFFF;
pub fn lpeek(address: u32) -> u8 {
unsafe { libc::lpeek(address as i32) }
}
pub unsafe fn lpoke(address: u32, value: u8) {
libc::lpoke(address as i32, value)
}
pub unsafe fn lcopy(source: u32, destination: u32, length: usize) {
if length > 0 {
unsafe { libc::lcopy(source as i32, destination as i32, length as u16) };
}
}
pub struct Allocator {
pub address: u32,
}
impl Allocator {
pub const fn new(address: u32) -> Self {
Self { address }
}
pub fn write(&mut self, bytes: &[u8]) -> Ptr28 {
let len = bytes.len();
let ptr = Ptr28 {
address: self.address,
len,
};
unsafe {
lcopy(bytes.as_ptr() as u32, self.address, len);
}
self.address += len as u32;
ptr
}
}
#[derive(Clone, Copy)]
pub struct Ptr28 {
pub address: u32,
pub len: usize,
}
impl From<Ptr28> for String {
fn from(value: Ptr28) -> Self {
unsafe { Self::from_utf8_unchecked(value.into()) }
}
}
impl From<Ptr28> for Vec<u8> {
fn from(value: Ptr28) -> Self {
MemoryIterator::new(value.address).get_chunk(value.len)
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct MemoryIterator {
pub address: u32,
}
impl MemoryIterator {
pub const fn new(address: u32) -> Self {
Self { address }
}
#[allow(clippy::uninit_vec)]
pub fn get_chunk(&mut self, n: usize) -> Vec<u8> {
let mut dst = Vec::<u8>::with_capacity(n);
unsafe {
dst.set_len(n);
lcopy(self.address, dst.as_mut_slice().as_ptr() as u32, n);
}
self.address += n as u32;
dst
}
}
impl Iterator for MemoryIterator {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
let value = lpeek(self.address);
self.address += 1;
Some(value)
}
#[allow(clippy::uninit_assumed_init)]
fn next_chunk<const N: usize>(
&mut self,
) -> Result<[Self::Item; N], core::array::IntoIter<Self::Item, N>>
where
Self: Sized,
{
let dst: [Self::Item; N] = unsafe { MaybeUninit::uninit().assume_init() };
unsafe {
lcopy(self.address, dst.as_ptr() as u32, N);
}
self.address += N as u32;
Ok(dst)
}
#[cfg(version("1.69"))]
fn advance_by(&mut self, n: usize) -> Result<(), core::num::NonZeroUsize> {
self.address += n as u32;
Ok(())
}
#[cfg(not(version("1.69")))]
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
self.address += n as u32;
Ok(())
}
}
impl Default for libc::dmagic_dmalist {
fn default() -> Self {
Self {
option_0b: 0x0b,
option_80: 0x80,
option_81: 0x81,
option_85: 0x85,
sub_cmd: 0x00,
end_of_options: 0x00,
dest_skip: 1,
source_addr: 0,
source_bank: 0,
source_mb: 0,
dest_addr: 0,
dest_bank: 0,
dest_mb: 0,
count: 0,
modulo: 0,
command: Self::COPY,
}
}
}
impl libc::dmagic_dmalist {
const COPY: u8 = 1;
pub fn do_dma(&self) {
let self_ptr = core::ptr::addr_of!(self) as u16;
unsafe {
libc::mega65_io_enable();
poke!(0xd702 as *mut u8, 0);
poke!(0xd704 as *mut u8, 0); poke!(0xd701 as *mut u8, (self_ptr >> 8) as u8);
poke!(0xd701 as *mut u8, (self_ptr & 0xff) as u8); }
}
fn set_source(&mut self, src: u32) {
self.source_mb = (src >> 20) as u8;
self.source_addr = (src & 0xffff) as u16;
self.source_bank = ((src >> 16) & 0x0f) as u8;
}
fn set_destinaion(&mut self, dst: u32) {
self.dest_mb = (dst >> 20) as u8;
self.dest_addr = (dst & 0xffff) as u16;
self.dest_bank = ((dst >> 16) & 0x0f) as u8;
}
fn init(&mut self) {
self.option_0b = 0x0b;
self.option_80 = 0x80;
self.option_81 = 0x81;
self.option_85 = 0x85;
self.sub_cmd = 0x00;
self.end_of_options = 0x00;
self.dest_skip = 1;
}
pub fn lpeek(&mut self, src: u32) -> u8 {
let dst: u8 = 0;
self.copy(src, (dst as *mut u8) as u32, 1);
dst
}
pub fn lpoke(&mut self, dst: u32, value: u8) {
self.copy((value as *mut u8) as u32, dst, 1);
}
pub fn copy(&mut self, src: u32, dst: u32, n: usize) {
self.command = Self::COPY;
self.count = n as u16;
self.init();
self.set_source(src);
self.set_destinaion(dst);
self.do_dma();
}
}