@@ -83,7 +83,10 @@ use rp_pico::{
8383} ;
8484
8585// Other Neotron Crates
86- use common:: MemoryRegion ;
86+ use common:: {
87+ video:: { Attr , TextBackgroundColour , TextForegroundColour } ,
88+ MemoryRegion ,
89+ } ;
8790use neotron_bmc_commands:: Command ;
8891use neotron_bmc_protocol:: Receivable ;
8992use neotron_common_bios as common;
@@ -290,8 +293,8 @@ fn main() -> ! {
290293 // VERSION has a trailing `\0` as that is what the BIOS/OS API requires.
291294 info ! ( "Neotron BIOS {} starting..." , VERSION . trim_matches( '\0' ) ) ;
292295
293- // Run at 126 MHz SYS_PLL, 48 MHz, USB_PLL. This is important, we as clock
294- // the PIO at ÷ 5 , to give 25.2 MHz (which is close enough to the 25.175
296+ // Run at 151.2 MHz SYS_PLL, 48 MHz, USB_PLL. This is important, we as clock
297+ // the PIO at ÷ 6 , to give 25.2 MHz (which is close enough to the 25.175
295298 // MHz standard VGA pixel clock).
296299
297300 // Step 1. Turn on the crystal.
@@ -302,23 +305,37 @@ fn main() -> ! {
302305 watchdog. enable_tick_generation ( ( rp_pico:: XOSC_CRYSTAL_FREQ / 1_000_000 ) as u8 ) ;
303306 // Step 3. Create a clocks manager.
304307 let mut clocks = hal:: clocks:: ClocksManager :: new ( pp. CLOCKS ) ;
305- // Step 4. Set up the system PLL. We take Crystal Oscillator (=12 MHz),
306- // ×126 (=1512 MHz), ÷6 (=252 MHz), ÷2 (=126 MHz)
308+ // Step 4. Set up the system PLL.
309+ //
310+ // We take the Crystal Oscillator (=12 MHz) with no divider, and ×126 to
311+ // give a FOUTVCO of 1512 MHz. This must be in the range 750 MHz - 1600 MHz.
312+ // The factor of 126 is calculated automatically given the desired FOUTVCO.
313+ //
314+ // Next we ÷5 on the first post divider to give 302.4 MHz.
315+ //
316+ // Finally we ÷2 on the second post divider to give 151.2 MHz.
317+ //
318+ // We note from the [RP2040
319+ // Datasheet](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf),
320+ // Section 2.18.2.1:
321+ //
322+ // > Jitter is minimised by running the VCO at the highest possible
323+ // > frequency, so that higher post-divide values can be used.
307324 let pll_sys = hal:: pll:: setup_pll_blocking (
308325 pp. PLL_SYS ,
309326 xosc. operating_frequency ( ) ,
310327 hal:: pll:: PLLConfig {
311328 vco_freq : 1512 . MHz ( ) ,
312329 refdiv : 1 ,
313- post_div1 : 6 ,
330+ post_div1 : 5 ,
314331 post_div2 : 2 ,
315332 } ,
316333 & mut clocks,
317334 & mut pp. RESETS ,
318335 )
319336 . map_err ( |_x| false )
320337 . unwrap ( ) ;
321- // Step 5. Set up a 48 MHz PLL for the USB system.
338+ // Step 5. Set up a 48 MHz PLL for the USB system.
322339 let pll_usb = hal:: pll:: setup_pll_blocking (
323340 pp. PLL_USB ,
324341 xosc. operating_frequency ( ) ,
@@ -1012,9 +1029,21 @@ impl Hardware {
10121029}
10131030
10141031fn sign_on ( ) {
1032+ static LOGO_TEXT : & str = "\
1033+ \n \
1034+ ╔═════════════════════════════════════════════════════════════════════════════╗\n \
1035+ ║ ▒▒▒ ▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒ ▒ ║\n \
1036+ ║ ▒ ▒▒ ▒ ▒ ▒ ▒ ▒▒ ▒ ▒ ▒ ▒ ▒ ▒▒ ▒ ║\n \
1037+ ║ ▒ ▒▒ ▒ ▒ ▒ ▒ ▒▒ ▒ ▒ ▒ ▒ ▒ ▒▒ ▒ ║\n \
1038+ ║ ▒ ▒▒ ▒ ▒▒▒▒▒ ▒ ▒ ▒▒ ▒▒▒▒▒ ▒ ▒ ▒ ▒▒ ▒ ║\n \
1039+ ║ ▒ ▒▒▒ ▒ ▒ ▒ ▒▒ ▒ ▒ ▒ ▒ ▒ ▒▒▒ ║\n \
1040+ ║ ▒ ▒▒▒ ▒ ▒ ▒ ▒▒ ▒ ▒ ▒ ▒ ▒ ▒▒▒ ║\n \
1041+ ║ ▒ ▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒ ▒ ▒ ▒▒▒▒▒▒ ▒ ▒▒ ║\n \
1042+ ╚═════════════════════════════════════════════════════════════════════════════╝\n ";
1043+
10151044 static LICENCE_TEXT : & str = "\
1016- Copyright © Jonathan 'theJPster' Pallant and the Neotron Developers, 2022\n \
10171045 \n \
1046+ Copyright © Jonathan 'theJPster' Pallant and the Neotron Developers, 2022\n \
10181047 This program is free software under GPL v3 (or later)\n ";
10191048
10201049 // Create a new temporary console for some boot-up messages
@@ -1023,14 +1052,37 @@ fn sign_on() {
10231052
10241053 // A crude way to clear the screen
10251054 for _col in 0 ..vga:: MAX_TEXT_ROWS {
1026- writeln ! ( & tc) . unwrap ( ) ;
1055+ writeln ! ( & tc, " " ) . unwrap ( ) ;
10271056 }
10281057
10291058 tc. move_to ( 0 , 0 ) ;
10301059
1031- writeln ! ( & tc, "Neotron Pico BIOS {}" , VERSION . trim_matches( '\0' ) ) . unwrap ( ) ;
1032- write ! ( & tc, "{}" , LICENCE_TEXT ) . unwrap ( ) ;
1033-
1060+ tc. change_attr ( Attr :: new (
1061+ TextForegroundColour :: BRIGHT_YELLOW ,
1062+ TextBackgroundColour :: BLUE ,
1063+ false ,
1064+ ) ) ;
1065+ write ! ( & tc, "{LOGO_TEXT}" ) . unwrap ( ) ;
1066+
1067+ tc. change_attr ( Attr :: new (
1068+ TextForegroundColour :: WHITE ,
1069+ TextBackgroundColour :: BLACK ,
1070+ false ,
1071+ ) ) ;
1072+ write ! ( & tc, "{LICENCE_TEXT}" ) . unwrap ( ) ;
1073+
1074+ tc. change_attr ( Attr :: new (
1075+ TextForegroundColour :: WHITE ,
1076+ TextBackgroundColour :: BLUE ,
1077+ false ,
1078+ ) ) ;
1079+ writeln ! ( & tc, "BIOS Version: {}" , VERSION . trim_matches( '\0' ) ) . unwrap ( ) ;
1080+
1081+ tc. change_attr ( Attr :: new (
1082+ TextForegroundColour :: WHITE ,
1083+ TextBackgroundColour :: DARK_RED ,
1084+ false ,
1085+ ) ) ;
10341086 let bmc_ver = critical_section:: with ( |cs| {
10351087 let mut lock = HARDWARE . borrow_ref_mut ( cs) ;
10361088 let hw = lock. as_mut ( ) . unwrap ( ) ;
@@ -1044,14 +1096,41 @@ fn sign_on() {
10441096 match bmc_ver {
10451097 Ok ( string_bytes) => match core:: str:: from_utf8 ( & string_bytes) {
10461098 Ok ( s) => {
1047- writeln ! ( & tc, "BMC Version: {s}" ) . unwrap ( ) ;
1099+ writeln ! ( & tc, "BMC Version: {}" , s . trim_matches ( '\0' ) ) . unwrap ( ) ;
10481100 }
10491101 Err ( _e) => {
1050- writeln ! ( & tc, "BMC Version: Unknown" ) . unwrap ( ) ;
1102+ writeln ! ( & tc, "BMC Version: Unknown" ) . unwrap ( ) ;
10511103 }
10521104 } ,
10531105 Err ( _e) => {
1054- writeln ! ( & tc, "BMC Version: Error reading" ) . unwrap ( ) ;
1106+ writeln ! ( & tc, "BMC Version: Error reading" ) . unwrap ( ) ;
1107+ }
1108+ }
1109+
1110+ tc. change_attr ( Attr :: new (
1111+ TextForegroundColour :: WHITE ,
1112+ TextBackgroundColour :: BLACK ,
1113+ false ,
1114+ ) ) ;
1115+ writeln ! ( & tc) . unwrap ( ) ;
1116+ writeln ! ( & tc) . unwrap ( ) ;
1117+
1118+ // Do a colour test
1119+ for bg in 0 ..=7 {
1120+ for fg in 0 ..=15 {
1121+ if fg != bg {
1122+ tc. change_attr (
1123+ // Safety: The loop above ensures bg and fg stay within bounds (0..=7 and 0..=15)
1124+ unsafe {
1125+ Attr :: new (
1126+ TextForegroundColour :: new_unchecked ( fg) ,
1127+ TextBackgroundColour :: new_unchecked ( bg) ,
1128+ false ,
1129+ )
1130+ } ,
1131+ ) ;
1132+ write ! ( & tc, "ABCabc123#!" ) . unwrap ( ) ;
1133+ }
10551134 }
10561135 }
10571136
@@ -1428,27 +1507,32 @@ pub extern "C" fn video_wait_for_line(line: u16) {
14281507 }
14291508}
14301509
1431- /// Read the RGB palette. Currently we only have two colours and you can't
1432- /// change them.
1510+ /// Read the RGB palette.
14331511extern "C" fn video_get_palette ( index : u8 ) -> common:: Option < common:: video:: RGBColour > {
1434- match index {
1435- 0 => common:: Option :: Some ( vga:: colours:: BLUE . into ( ) ) ,
1436- 1 => common:: Option :: Some ( vga:: colours:: YELLOW . into ( ) ) ,
1437- _ => common:: Option :: None ,
1438- }
1512+ let raw_u16 = vga:: VIDEO_PALETTE [ index as usize ] . load ( Ordering :: Relaxed ) ;
1513+ let our_colour = vga:: RGBColour ( raw_u16) ;
1514+ // Convert from our 12-bit colour type to the public 24-bit colour type
1515+ common:: Option :: Some ( our_colour. into ( ) )
14391516}
14401517
1441- /// Update the RGB palette
1442- extern "C" fn video_set_palette ( _index : u8 , _rgb : common:: video:: RGBColour ) {
1443- // TODO set the palette when we actually have one
1518+ /// Update the RGB palette.
1519+ extern "C" fn video_set_palette ( index : u8 , rgb : common:: video:: RGBColour ) {
1520+ // Convert from their 24-bit colour type to our 12-bit colour type
1521+ let our_colour: vga:: RGBColour = rgb. into ( ) ;
1522+ // Store it
1523+ vga:: VIDEO_PALETTE [ index as usize ] . store ( our_colour. 0 , Ordering :: Relaxed ) ;
14441524}
14451525
14461526/// Update all the RGB palette
14471527unsafe extern "C" fn video_set_whole_palette (
1448- _palette : * const common:: video:: RGBColour ,
1449- _length : usize ,
1528+ palette : * const common:: video:: RGBColour ,
1529+ length : usize ,
14501530) {
1451- // TODO set the palette when we actually have one
1531+ // Don't let them set more than 255 entries
1532+ let num_entries = length. min ( 255 ) ;
1533+ for i in 0 ..num_entries {
1534+ video_set_palette ( i as u8 , palette. add ( i) . read ( ) )
1535+ }
14521536}
14531537
14541538extern "C" fn i2c_bus_get_info ( _i2c_bus : u8 ) -> common:: Option < common:: i2c:: BusInfo > {
@@ -1629,6 +1713,7 @@ extern "C" fn block_dev_eject(_dev_id: u8) -> common::Result<()> {
16291713/// Sleep the CPU until the next interrupt.
16301714extern "C" fn power_idle ( ) {
16311715 if !INTERRUPT_PENDING . load ( Ordering :: Relaxed ) {
1716+ defmt:: debug!( "Idle..." ) ;
16321717 cortex_m:: asm:: wfe ( ) ;
16331718 }
16341719}
0 commit comments