Skip to content

Commit 8939b86

Browse files
Merge pull request #46 from Neotron-Compute/faster-text-mode-2
Adds full colour 80 column support.
2 parents 9a9fd93 + 2d773f8 commit 8939b86

6 files changed

Lines changed: 588 additions & 435 deletions

File tree

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ codegen-units = 1
5555
debug = true
5656
# better optimizations
5757
lto = true
58+
# Set the optimisation level to optimise for space. This also happens to be a
59+
# good choice for performance on the RP2040, where code executes from external
60+
# SPI Flash and has to be buffered in a small on-chip cache memory.
61+
opt-level = "s"
5862

5963
[patch.crates-io]
6064
rp2040-boot2 = { version = "0.3.0", git = "https://github.com/rp-rs/rp2040-boot2" }

memory.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ MEMORY {
2828
RAM_OS : ORIGIN = 0x20000000, LENGTH = 0x3A000
2929
/*
3030
* This is the top of the four striped banks of SRAM in the RP2040.
31+
*
32+
* We give ourselves six 4K pages [0x3A_000, 0x40_000]
3133
*/
3234
RAM : ORIGIN = 0x2003A000, LENGTH = 24K
3335
/*

src/main.rs

Lines changed: 113 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
};
8790
use neotron_bmc_commands::Command;
8891
use neotron_bmc_protocol::Receivable;
8992
use 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

10141031
fn 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.
14331511
extern "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
14471527
unsafe 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

14541538
extern "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.
16301714
extern "C" fn power_idle() {
16311715
if !INTERRUPT_PENDING.load(Ordering::Relaxed) {
1716+
defmt::debug!("Idle...");
16321717
cortex_m::asm::wfe();
16331718
}
16341719
}
3.55 KB
Binary file not shown.

src/thumbv6m-none-eabi-flash1002-libneotron_os.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
This is Neotron OS version v0.3.0
1+
This is Neotron OS version v0.3.1
22

3-
Taken from https://github.com/Neotron-Compute/Neotron-OS/releases/tag/v0.3.0
3+
Taken from https://github.com/Neotron-Compute/Neotron-OS/releases/tag/v0.3.1
44

55
This program is free software: you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by

0 commit comments

Comments
 (0)