From 1da460cd41bd13014f7e51679bd37f89ffb79db9 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 18 Aug 2020 12:07:41 +0800 Subject: [PATCH] examples: fix betrusted LCD under Renode This gets the Betrusted LCD demo working within emulation, which means it ought to work on real hardware. Signed-off-by: Sean Cross --- emulation/csr.csv | 4 +- .../graphics-server/src/backend/betrusted.rs | 88 +++++++++++++------ 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/emulation/csr.csv b/emulation/csr.csv index 00d283851..c1286795a 100644 --- a/emulation/csr.csv +++ b/emulation/csr.csv @@ -21,8 +21,8 @@ csr_base,spinor,0xf0008000,, csr_base,audio,0xf000a800,, csr_base,ctrl,0xf0000000,, csr_base,uart,0xf0001800,, -csr_base,memlcd,0xf0004800,, -csr_base,com,0xf0005000,, +csr_base,memlcd,0xf0005000,, +csr_base,com,0xf000c000,, csr_register,i2c_prescale,0xf0005800,1,rw csr_register,messible_in,0xf0006800,1,rw csr_register,i2c_command,0xf0005810,1,rw diff --git a/examples/graphics-server/src/backend/betrusted.rs b/examples/graphics-server/src/backend/betrusted.rs index 1c9e7bf2e..e36405b68 100644 --- a/examples/graphics-server/src/backend/betrusted.rs +++ b/examples/graphics-server/src/backend/betrusted.rs @@ -1,4 +1,5 @@ use embedded_graphics::{drawable::Pixel, geometry::Size, pixelcolor::BinaryColor, DrawTarget}; +use xous::MemoryRange; const FB_WIDTH_WORDS: usize = 11; const FB_WIDTH_PIXELS: usize = 336; @@ -6,26 +7,37 @@ const FB_LINES: usize = 536; const FB_SIZE: usize = FB_WIDTH_WORDS * FB_LINES; // 44 bytes by 536 lines const CONFIG_CLOCK_FREQUENCY: u32 = 100_000_000; -// const MAX_FPS: u64 = 15; - const COMMAND_OFFSET: usize = 0; const BUSY_OFFSET: usize = 1; const PRESCALER_OFFSET: usize = 2; pub struct XousDisplay { - fb: &'static mut [u32; FB_WIDTH_PIXELS * FB_LINES], - control: *mut u32, + fb: MemoryRange, + control: MemoryRange, } impl XousDisplay { pub fn new() -> XousDisplay { - let fb = unsafe { &mut *(0xb000_0000 as *mut [u32; FB_WIDTH_PIXELS * FB_LINES]) }; - let mut display = XousDisplay { - fb, - control: 0xf000_a000u32 as _, - }; + let fb = xous::syscall::map_memory( + xous::MemoryAddress::new(0xb000_0000), + None, + ((FB_WIDTH_WORDS * FB_LINES * 4) + 4096) & !4095, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("couldn't map control port"); + + let control = xous::syscall::map_memory( + xous::MemoryAddress::new(0xf000_5000), + None, + 4096, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("couldn't map control port"); + let mut display = XousDisplay { fb, control }; + display.set_clock(CONFIG_CLOCK_FREQUENCY); display.sync_clear(); + display } @@ -41,28 +53,37 @@ impl XousDisplay { /// fn set_clock(&mut self, clk_mhz: u32) { unsafe { - self.control + (self.control.as_ptr() as *mut u32) .add(PRESCALER_OFFSET) .write_volatile((clk_mhz / 2_000_000) - 1); } } fn update_all(&mut self) { - unsafe { self.control.add(COMMAND_OFFSET).write_volatile(2) }; + unsafe { + (self.control.as_ptr() as *mut u32) + .add(COMMAND_OFFSET) + .write_volatile(2) + }; } fn update_dirty(&mut self) { - unsafe { self.control.add(COMMAND_OFFSET).write_volatile(1) }; + unsafe { + (self.control.as_ptr() as *mut u32) + .add(COMMAND_OFFSET) + .write_volatile(1) + }; } /// "synchronous clear" -- must be called on init, so that the state of the LCD /// internal memory is consistent with the state of the frame buffer fn sync_clear(&mut self) { + let framebuffer = self.fb.as_mut_ptr() as *mut u32; for words in 0..FB_SIZE { if words % FB_WIDTH_WORDS != 10 { - self.fb[words] = 0xFFFF_FFFF; + unsafe { framebuffer.add(words).write_volatile(0xFFFF_FFFF) }; } else { - self.fb[words] = 0x0000_FFFF; + unsafe { framebuffer.add(words).write_volatile(0x0000_FFFF) }; } } self.update_all(); // because we force an all update here @@ -70,35 +91,46 @@ impl XousDisplay { } fn busy(&self) -> bool { - unsafe { self.control.add(BUSY_OFFSET).read_volatile() == 1 } + unsafe { + (self.control.as_ptr() as *mut u32) + .add(BUSY_OFFSET) + .read_volatile() + == 1 + } } } impl DrawTarget for XousDisplay { type Error = core::convert::Infallible; - /// Draw a `Pixel` that has a color defined as `Gray8`. + /// Draw a `Pixel` that has a color defined as `BinaryColor`. fn draw_pixel(&mut self, pixel: Pixel) -> Result<(), Self::Error> { let Pixel(coord, color) = pixel; + let framebuffer = self.fb.as_mut_ptr() as *mut u32; + let offset = (coord.x / 32 + coord.y * FB_WIDTH_WORDS as i32) as usize; match color { BinaryColor::Off => { - self.fb[(coord.x / 32 + coord.y * FB_WIDTH_WORDS as i32) as usize] |= - 1 << (coord.x % 32) + unsafe { + framebuffer.add(offset).write_volatile( + framebuffer.add(offset).read_volatile() | (1 << (coord.x % 32)), + ) + }; } BinaryColor::On => { - self.fb[(coord.x / 32 + coord.y * FB_WIDTH_WORDS as i32) as usize] &= - !(1 << (coord.x % 32)) + unsafe { + framebuffer.add(offset).write_volatile( + framebuffer.add(offset).read_volatile() & !(1 << (coord.x % 32)), + ) + }; } } - // set the dirty bit on the line - self.fb[(coord.y * FB_WIDTH_WORDS as i32 + (FB_WIDTH_WORDS as i32 - 1)) as usize] |= - 0x1_0000; - // self.buffer[(point.y * (WIDTH as i32) + point.x) as usize] = if color == BinaryColor::On { - // LIGHT_COLOUR - // } else { - // DARK_COLOUR - // }; + // set the dirty bit on the line + unsafe { + framebuffer + .add(offset) + .write_volatile(framebuffer.add(offset).read_volatile() | 0x1_0000) + }; Ok(()) }