1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// copyright 2022 mikael lund aka wombat
// 
// licensed under the apache license, version 2.0 (the "license");
// you may not use this file except in compliance with the license.
// you may obtain a copy of the license at
// 
//     http://www.apache.org/licenses/license-2.0
// 
// unless required by applicable law or agreed to in writing, software
// distributed under the license is distributed on an "as is" basis,
// without warranties or conditions of any kind, either express or implied.
// see the license for the specific language governing permissions and
// limitations under the license.

//! This crate contains hardware register tables and support functions for
//! 8-bit retro computers like the Commodore 64, MEGA65 and others.
//! Please check the `examples/` directory to see how Rust can be
//! used generate demo effects.
//!
//! # Examples
//! 
//! Read and write to labelled hardware registers:
//! 
//! ```
//! use mos_hardware::{c64,vic2};
//! 
//! let old_border_color = (*c64::VIC).border_color.read();
//! (*c64::VIC).border_color.write(c64::LIGHT_RED);
//! 
//! (*c64::SID).potentiometer_x.write(3); // error: read-only register
//! ```
//! 
//! Use bitflags to control hardware behaviour, _e.g._ where the VIC-II chip accesses
//! screen memory and character sets:
//! 
//! ```
//! let bank = vic2::ScreenBank::AT_2C00.bits() | vic2::CharsetBank::AT_2000.bits();
//! (*c64::VIC).screen_and_charset_bank.write(bank);
//! ```
//! 
//! Convenience functions to perform hardware-specific tasks, _e.g._ generate random numbers
//! using noise from the C64's SID chip:
//! 
//! ```
//! (*c64::SID).start_random_generator();
//! let random_number : u8 = rand8!(c64::SID);
//! ```
//!

#![no_std]

extern crate static_assertions;

pub mod cia;
pub mod sid;
pub mod vic2;
pub mod c64;
pub mod mega65;

use core::iter::Iterator;

/**
 * Peek into memory (read)
 *
 * Example:
 *
 *     let value = peek!(0xC000 as *mut u8);
 */
#[macro_export]
macro_rules! peek {
    ($address:expr) => {{
        #[allow(unused_unsafe)]
        unsafe {
            core::ptr::read_volatile($address)
        }
    }};
}

/**
 * Poke into memory (read)
 *
 * Example:
 *
 *     poke!(0xD020 as *mut u8, vic2::LIGHT_GREEN);
 */
#[macro_export]
macro_rules! poke {
    ($address:expr, $value:expr) => {{
        #[allow(unused_unsafe)]
        unsafe {
            core::ptr::write_volatile($address, $value);
        }
    }};
}

/// Add two integers using wrapping
#[macro_export]
macro_rules! add {
    ($value1:expr, $value2:expr) => {{
        $value1.wrapping_add($value2)
    }};
}

/// Subtract two integers using wrapping
#[macro_export]
macro_rules! sub {
    ($value1:expr, $value2:expr) => {{
        $value1.wrapping_sub($value2)
    }};
}

/**
 * Repeat each element n times
 *
 * See more
 * [here](https://stackoverflow.com/questions/66482699/how-to-repeat-each-element-of-iterator-n-times).
 */
pub fn repeat_element<T: Clone>(
    it: impl Iterator<Item = T>,
    cnt: usize,
) -> impl Iterator<Item = T> {
    it.flat_map(move |n| core::iter::repeat(n).take(cnt))
}