mos_hardware/mega65/mod.rs
1// copyright 2022 mikael lund aka wombat
2//
3// licensed under the apache license, version 2.0 (the "license");
4// you may not use this file except in compliance with the license.
5// you may obtain a copy of the license at
6//
7// http://www.apache.org/licenses/license-2.0
8//
9// unless required by applicable law or agreed to in writing, software
10// distributed under the license is distributed on an "as is" basis,
11// without warranties or conditions of any kind, either express or implied.
12// see the license for the specific language governing permissions and
13// limitations under the license.
14
15//! MEGA65 support.
16//!
17//! The MEGA65 is a 100% open-source implementation of the official (but never-released)
18//! Commodore 65 computer. It is in development by associates of the Museum of Electronic
19//! Games and Art e. V., a not-for-profit institution "dedicated to the preservation of
20//! our digital heritage." As well as the original C65 design, the MEGA65 provides
21//! additional hardware and software enhancements, including a choice of using BASIC 10 or
22//! BASIC 65 (containing improvements that go beyond BASIC 10).
23//! The MEGA65 has an 8-bit CPU with additional 32-bit instructions implemented in FPGA.
24//! Like the original C65, it also has a Commodore 64 mode with a level of compatibility
25//! similar to that of the Commodore 128 running in C64 mode
26
27use crate::sid::*;
28use crate::vic2::*;
29use crate::{peek, petscii, poke};
30
31pub mod iomap;
32pub mod libc;
33pub mod math;
34mod memory;
35pub mod random;
36pub use memory::*;
37
38/// Default system palette
39///
40/// The following table is extracted from the MEGA65 user guide.
41///
42/// Code | Red | Green | Blue | Name | HTML color
43/// ---- | ----- | ----- | ----- | ---------------- | -----------
44/// 0 | 0 | 0 | 0 | Black | #000000
45/// 1 | 15 | 15 | 15 | White | #FFFFFF
46/// 2 | 15 | 0 | 0 | Red | #FF0000
47/// 3 | 0 | 15 | 15 | Cyan | #00FFFF
48/// 4 | 15 | 0 | 15 | Purple | #FF00FF
49/// 5 | 0 | 15 | 0 | Green | #00FF00
50/// 6 | 0 | 0 | 15 | Blue | #0000FF
51/// 7 | 15 | 15 | 0 | Yellow | #FFFF00
52/// 8 | 15 | 6 | 0 | Orange | #FF6F00
53/// 9 | 10 | 4 | 0 | Brown | #A04000
54/// 10 | 15 | 7 | 7 | Light Red (Pink) | #FF7777
55/// 11 | 5 | 5 | 5 | Dark Grey | #050505
56/// 12 | 8 | 8 | 8 | Medium Grey | #080808
57/// 13 | 9 | 15 | 9 | Light Green | #09FF09
58/// 14 | 9 | 9 | 15 | Light Blue | #0909FF
59/// 15 | 11 | 11 | 11 | Light Grey | #0B0B0B
60/// 16 | 14 | 0 | 0 | Guru Meditation | #E00000
61/// 17 | 15 | 5 | 0 | Rambutan | #FF5000
62/// 18 | 15 | 11 | 0 | Carrot | #FF6F00
63/// 19 | 14 | 14 | 0 | Lemon Tart | #8E8E00
64/// 20 | 7 | 15 | 0 | Pandan | #07FF00
65/// 21 | 6 | 14 | 6 | Seasick Green | #06E606
66/// 22 | 0 | 14 | 3 | Soylent Green | #00E003
67/// 23 | 0 | 15 | 9 | Slimer Green | #00FF09
68/// 24 | 0 | 13 | 13 | The Other Cyan | #00DDDD
69/// 25 | 0 | 9 | 15 | Sea Sky | #009FFF
70/// 26 | 0 | 3 | 15 | Smurf Blue | #003FFF
71/// 27 | 0 | 0 | 14 | Screen of Death | #0000E0
72/// 28 | 7 | 0 | 15 | Plum Sauce | #0700FF
73/// 29 | 12 | 0 | 15 | Sour Grape | #0C00FF
74/// 30 | 15 | 0 | 11 | Bubblegum | #FF0B0B
75/// 31 | 15 | 3 | 6 | Hot Tamales | #FF0306
76#[repr(u8)]
77#[derive(Debug, Copy, Clone, PartialEq)]
78pub enum DefaultPalette {
79 /// Black color (<a style="color:#000000;">●</a>)
80 Black = 0,
81 /// White color (<a style="color:#FFFFFF;">●</a>)
82 White = 1,
83 /// Red color (<a style="color:#FF0000;">●</a>)
84 Red = 2,
85 /// Cyan color (<a style="color:#00FFFF;">●</a>)
86 Cyan = 3,
87 /// Purple color (<a style="color:#FF00FF;">●</a>)
88 Purple = 4,
89 /// Green color (<a style="color:#00FF00;">●</a>)
90 Green = 5,
91 /// Blue color (<a style="color:#0000FF;">●</a>)
92 Blue = 6,
93 /// Yellow color (<a style="color:#FFFF00;">●</a>)
94 Yellow = 7,
95 /// Orange color (<a style="color:#FF6F00;">●</a>)
96 Orange = 8,
97 /// Brown color (<a style="color:#A04000;">●</a>)
98 Brown = 9,
99 /// Light Red (Pink) color (<a style="color:#FF7777;">●</a>)
100 LightRed = 10,
101 /// Dark Grey color (<a style="color:#050505;">●</a>)
102 DarkGrey = 11,
103 /// Medium Grey color (<a style="color:#080808;">●</a>)
104 MediumGrey = 12,
105 /// Light Green color (<a style="color:#09FF09;">●</a>)
106 LightGreen = 13,
107 /// Light Blue color (<a style="color:#0909FF;">●</a>)
108 LightBlue = 14,
109 /// Light Grey color (<a style="color:#0B0B0B;">●</a>)
110 LightGrey = 15,
111 /// Guru Meditation color (<a style="color:#E00000;">●</a>)
112 GuruMeditation = 16,
113 /// Rambutan color (<a style="color:#FF5000;">●</a>)
114 Rambutan = 17,
115 /// Carrot color (<a style="color:#FF6F00;">●</a>)
116 Carrot = 18,
117 /// Lemon Tart color (<a style="color:#8E8E00;">●</a>)
118 LemonTart = 19,
119 /// Pandan color (<a style="color:#07FF00;">●</a>)
120 Pandan = 20,
121 /// Seasick Green color (<a style="color:#06E606;">●</a>)
122 SeasickGreen = 21,
123 /// Soylent Green color (<a style="color:#00E003;">●</a>)
124 SoylentGreen = 22,
125 /// Slimer Green color (<a style="color:#00FF09;">●</a>)
126 SlimerGreen = 23,
127 /// The Other Cyan color (<a style="color:#00DDDD;">●</a>)
128 TheOtherCyan = 24,
129 /// Sea Sky color (<a style="color:#009FFF;">●</a>)
130 SeaSky = 25,
131 /// Smurf Blue color (<a style="color:#003FFF;">●</a>)
132 SmurfBlue = 26,
133 /// Screen of Death color (<a style="color:#0000E0;">●</a>)
134 ScreenOfDeath = 27,
135 /// Plum Sauce color (<a style="color:#0700FF;">●</a>)
136 PlumSauce = 28,
137 /// Sour Grape color (<a style="color:#0C00FF;">●</a>)
138 SourGrape = 29,
139 /// Bubblegum color (<a style="color:#FF0B0B;">●</a>)
140 Bubblegum = 30,
141 /// Hot Tamales color (<a style="color:#FF0306;">●</a>)
142 HotTamales = 31,
143}
144
145pub const DEFAULT_SCREEN: *mut u8 = (0x0800) as *mut u8;
146pub const DEFAULT_UPPERCASE_FONT: *mut u8 = (0x1000) as *mut u8;
147pub const DEFAULT_MIXEDCASE_FONT: *mut u8 = (0x1800) as *mut u8;
148
149pub const VICII: *const MOSVideoInterfaceControllerII =
150 (0xd000) as *const MOSVideoInterfaceControllerII;
151
152/// Pointer to first sound interface device
153pub const SID0: *const MOSSoundInterfaceDevice = (0xd400) as *const MOSSoundInterfaceDevice;
154/// Pointer to second sound interface device
155pub const SID1: *const MOSSoundInterfaceDevice = (0xd420) as *const MOSSoundInterfaceDevice;
156/// Pointer to third sound interface device
157pub const SID2: *const MOSSoundInterfaceDevice = (0xd440) as *const MOSSoundInterfaceDevice;
158/// Pointer to fourth sound interface device
159pub const SID3: *const MOSSoundInterfaceDevice = (0xd460) as *const MOSSoundInterfaceDevice;
160
161pub const COLOR_RAM: *mut u8 = (0xd800) as *mut u8;
162
163/// Math multiplication-division status flags
164pub const MATH_STATUS: *const volatile_register::RO<math::StatusFlags> =
165 (0xd70f) as *const volatile_register::RO<math::StatusFlags>;
166
167/// Math Acceleration registers
168pub const MATH_ACCELERATOR: *const math::MathAccelerator = (0xd768) as *const math::MathAccelerator;
169
170pub enum VicBank {
171 Region0000 = 0x11, // Bank 0
172 Region4000 = 0x10, // Bank 1
173 Region8000 = 0x01, // Bank 2
174 RegionC000 = 0x00, // Bank 3
175}
176
177/// Get reference to VIC2 chip
178pub const fn vic2() -> &'static MOSVideoInterfaceControllerII {
179 unsafe { &*VICII }
180}
181
182/// Get reference to first SID chip
183pub const fn sid0() -> &'static MOSSoundInterfaceDevice {
184 unsafe { &*SID0 }
185}
186
187/// Get reference to second SID chip
188pub const fn sid1() -> &'static MOSSoundInterfaceDevice {
189 unsafe { &*SID1 }
190}
191
192/// Get reference to third SID chip
193pub const fn sid2() -> &'static MOSSoundInterfaceDevice {
194 unsafe { &*SID2 }
195}
196
197/// Get reference to fourth SID chip
198pub const fn sid3() -> &'static MOSSoundInterfaceDevice {
199 unsafe { &*SID3 }
200}
201
202/// Get reference to math accelerator
203pub const fn math_accelerator() -> &'static math::MathAccelerator {
204 unsafe { &*MATH_ACCELERATOR }
205}
206
207/// Set CPU speed to 1 Mhz
208pub fn speed_mode1() {
209 unsafe {
210 let mut val: u8 = peek!(0xd031 as *mut u8) & 0b1011_1111; // unset FAST bit
211 poke!(0xd031 as *mut u8, val);
212 val = peek!(0xd054 as *mut u8) & 0b1011_1111; // unset VFAST bit
213 poke!(0xd054 as *mut u8, val);
214 }
215}
216
217/// Set CPU speed to 3.5 Mhz
218pub fn speed_mode3() {
219 unsafe {
220 let mut val: u8 = peek!(0xd031 as *mut u8) | 0b0100_0000; // set FAST bit
221 poke!(0xd031 as *mut u8, val);
222 val = peek!(0xd054 as *mut u8) & 0b1011_1111; // unset VFAST
223 poke!(0xd054 as *mut u8, val);
224 }
225}
226
227/// Set CPU speed to 40 Mhz
228pub fn speed_mode40() {
229 unsafe {
230 let mut val: u8 = peek!(0xd031 as *mut u8) | 0b0100_0000; // set FAST bit
231 poke!(0xd031 as *mut u8, val);
232 val = peek!(0xd054 as *mut u8) | 0b0100_0000; // set VFAST bit
233 poke!(0xd054 as *mut u8, val);
234 }
235}
236
237/// Struct used to store widht-height resolutions
238#[derive(Default)]
239pub struct Resolution<T> {
240 pub width: T,
241 pub height: T,
242}
243
244/// Returns screen resolution (char width, char heigh)
245pub fn get_screen_size() -> Resolution<u8> {
246 let mut resolution = Resolution::default();
247 unsafe {
248 libc::getscreensize(&mut resolution.width, &mut resolution.height);
249 }
250 resolution
251}
252
253/// Initialises the conio internal state
254///
255/// This must be called before using any conio library function.
256pub fn conio_init() {
257 unsafe {
258 libc::conioinit();
259 }
260}
261
262/// Shift to lower case ROM charset
263pub fn set_lower_case() {
264 unsafe {
265 libc::setlowercase();
266 }
267}
268
269/// Shift to upper case ROM charset
270pub fn set_upper_case() {
271 unsafe {
272 libc::setuppercase();
273 }
274}
275
276/// Clear all chars on screen
277pub fn clear_screen() {
278 unsafe {
279 libc::clrscr();
280 }
281}
282
283/// Goto top left corner
284pub fn go_home() {
285 unsafe {
286 libc::gohome();
287 }
288}
289
290/// Goto specific character position
291pub fn goto_xy(x: u8, y: u8) {
292 unsafe {
293 libc::gotoxy(x, y);
294 }
295}
296
297/// Output multiple screen codes at X,Y coordinates
298///
299/// Works with _null-terminated_ screen codes only.
300///
301/// # Examples
302/// ~~~
303/// use mos_hardware::{petscii, petscii_null}
304/// mega65::cputs_xy(2, 3, [8, 5, 12, 12, 15, 0].as_slice());
305/// mega65::cputs_xy(4, 6, petscii_null!("hello").as_slice());
306/// ~~~
307pub fn cputs_xy(x: u8, y: u8, screen_codes: &[u8]) {
308 assert_eq!(*screen_codes.last().unwrap(), 0u8);
309 unsafe {
310 libc::cputsxy(x, y, screen_codes.as_ptr());
311 }
312}
313
314/// Output screen codes at current position
315///
316/// Works with _null-terminated_ screen codes only.
317///
318/// # Examples
319/// ~~~
320/// use mos_hardware::{petscii, petscii_null}
321/// mega65::cputs(petscii_null!("hello").as_slice());
322/// ~~~
323pub fn cputs(screen_codes: &[u8]) {
324 assert_eq!(*screen_codes.last().unwrap(), 0u8);
325 unsafe {
326 libc::cputs(screen_codes.as_ptr());
327 }
328}
329
330/// Flush keyboard buffer
331pub fn flush_keyboard_buffer() {
332 unsafe {
333 libc::flushkeybuf();
334 }
335}
336
337/// Waits until a character is in the keyboard buffer and returns as petscii
338pub fn cgetc() -> petscii::Petscii {
339 unsafe { libc::cgetc() }.into()
340}
341
342/// Sets the current border color
343pub fn set_border_color(color: u8) {
344 unsafe {
345 libc::bordercolor(color);
346 }
347}
348
349/// Sets the current screen (background) color
350pub fn set_background_color(color: u8) {
351 unsafe {
352 libc::bgcolor(color);
353 }
354}
355
356/// Sets the current text color
357pub fn set_text_color(color: u8) {
358 unsafe {
359 libc::textcolor(color);
360 }
361}
362
363/// Read real time clock
364///
365/// # Examples
366/// ~~~
367/// let rtc = mega65::get_real_time_clock();
368/// println!("TIME = {}:{}:{}", rtc.tm_hour, rtc.tm_min, rtc.tm_sec);
369/// ~~~
370pub fn get_real_time_clock() -> libc::m65_tm {
371 let mut rtc = libc::m65_tm::default();
372 unsafe {
373 libc::getrtc(&mut rtc);
374 }
375 rtc
376}
377
378/// Sets VIC-III extended attributes mode to enable blink, underline, bold, highlight
379pub fn set_extended_attributes() {
380 unsafe {
381 libc::setextendedattrib(1);
382 }
383}
384
385/// Clears VIC-III extended attributes mode to disable blink, underline, bold, highlight
386pub fn unset_extended_attributes() {
387 unsafe {
388 libc::setextendedattrib(0);
389 }
390}
391
392/// Set character set address using mega65-libc
393pub fn set_charset_address(address: u16) {
394 unsafe {
395 libc::setcharsetaddr(address as i32);
396 }
397}