diff --git a/examples/data_mem.rs b/examples/data_mem.rs index 73181852..21a25078 100644 --- a/examples/data_mem.rs +++ b/examples/data_mem.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::{ops::Range, path::PathBuf}; use syncrim::{ common::{ComponentStore, Input, SignalUnsigned}, components::*, @@ -22,6 +22,10 @@ fn main() { Input::new("ctrl", "out"), Input::new("sext", "out"), Input::new("size", "out"), + Range { + start: 0, + end: 0x20, + }, // later history... tbd ), Constant::rc_new("data", (100.0, 100.0), 3), diff --git a/riscv/Cargo.toml b/riscv/Cargo.toml index cbdbecb5..c43f1db2 100644 --- a/riscv/Cargo.toml +++ b/riscv/Cargo.toml @@ -16,6 +16,7 @@ log = "0.4.19" num_enum = "0.6.1" fern = "0.6.2" xmas-elf = "0.9.0" +asm_riscv = "0.1.0" [dependencies.syncrim] path = "../" diff --git a/riscv/asm.s b/riscv/asm.s index 740830c2..03f5000d 100644 --- a/riscv/asm.s +++ b/riscv/asm.s @@ -1,10 +1,319 @@ -.section .text +.option arch, rv32i +# ---------------------------------------------------------- +# Group 1's "underlag" for Lab 1 +# Pseudo-instructions may be used for Lab 1. +# ---------------------------------------------------------- + + + +# Group 1's Codeword Generator Subroutine (pseudocode) +# (remember: "seed" is a global variable, UNSIGNED INTEGER; +# you may implement local variables in registers or on the stack; +# result returned in v0; preserve all except t regs) +# +# FUNCTION codgen(): UNSIGNED INTEGER; +# LOCAL SIGNED INTEGER n; +# LOCAL UNSIGNED INTEGER x, y; +# BEGIN +# n := [count the number of 0's in word "seed"]; +# x := [rotate "seed" left by 30 bits]; +# y := [shift "seed" right-ARITHMETIC by 6 bits]; +# seed := x XOR y XOR n; +# RETURN( seed XOR 0x464b713e ); +# END; +# +# hint: if "seed" is initialized to 0x3e944b9f, +# the first five calls will generate these values: +# 0x891432f9, 0x4aa1dccc, 0xc54270fa, 0x9885155f, 0xce83d1b8, ... +# your code is to be written farther down (see comment below). + + +# Group 1's Recursive Decoding Subroutine (pseudocode) +# (for "decode", all four local variables must be implemented ON THE +# STACK, and NOT in registers; implement the code literally,. +# no optimizations. We're trying to teach you something. +# remember: result returned in v0; preserve all except t regs) +# +# FUNCTION decode( wordarr, bytearr ): UNSIGNED INTEGER; +# (wordarr, bytearr passed by reference) +# LOCAL UNSIGNED INTEGER m, r, x, y; +# BEGIN +# x := ONE'S-COMPLEMENT of codgen(); +# IF ([contents of word at "wordarr"] = 0) THEN +# [byte pointed to by "bytearr"] := 0; +# r := x; +# ELSE +# y := decode( wordarr+, bytearr+ ); # "k+" means "successor in k" +# m := ( x - y ) - [contents of word at "wordarr"]; +# [byte pointed to by "bytearr"] := [the eight bits at "m"<20:13>]; +# r := TWO'S-COMPLEMENT OF codgen(); +# r := x + y + m + r + 5; +# ENDIF; +# RETURN( r ); +# END; + + +# ---------------------------------------------------------- +# The following are the ONLY lines that may appear in the +# ".data" section of the code. You may add NO other lines. +# NO additional global variables. +# ---------------------------------------------------------- + + + .data +test_word: .word 0xDEADBEEF +some_string: .string "Hi! :)" +.align 4 +abc: .word 0x9fdd9158 # string "abc", encoded + .word 0x85715808 + .word 0xac73323a + .word 0 +plain: .space 132 # room for 132 characters + + .align 4 +seed: .word 0 # 32-bit UNSIGNED INTEGER. + +coded: .word 0x015e7a47 # the real encoded data + .word 0x2ef84ebb + .word 0x177a8db4 + .word 0x1b722ff9 + .word 0x5dc7cff0 + .word 0x5dc9dea6 + .word 0x1da0c15a + .word 0xe4c236a2 + .word 0x3d16b0d0 + .word 0x1f397842 + .word 0xaae0d2ba + .word 0x11246674 + .word 0x0845317f + .word 0xd5512dad + .word 0xb6184977 + .word 0xd293a53e + .word 0x7d9c2716 + .word 0xd917eae6 + .word 0xd8852384 + .word 0x286e46f9 + .word 0xce566029 + .word 0xcefe7daf + .word 0x62d726d4 + .word 0x0dbaeb2d + .word 0x95f57c60 + .word 0xed515141 + .word 0x29b77d0f + .word 0x9f7b8d0c + .word 0x45a8395a + .word 0xfead2b72 + .word 0x883d434c + .word 0xed8ddf60 + .word 0xe51e65e4 + .word 0x19bf6bb1 + .word 0xfeb505ec + .word 0x662aa23c + .word 0xf6827cf8 + .word 0xd1dc7a5c + .word 0x4fa5b066 + .word 0x7ddd25a4 + .word 0xa8ba8e8a + .word 0x72846227 + .word 0xf8f636fb + .word 0x2b389a9c + .word 0xe4038bf6 + .word 0x6e169877 + .word 0xad028132 + .word 0x84dbfe8c + .word 0x243762ff + .word 0x59c8f80c + .word 0xb6e0db4b + .word 0xedb8cab7 + .word 0xcd4b39f6 + .word 0xaf263741 + .word 0x18d9965f + .word 0x1ab1f037 + .word 0x5b458792 + .word 0xc94d960d + .word 0xd45cedea + .word 0x2160aca3 + .word 0x93c77766 + .word 0x2d66e105 + .word 0x9ff74d4f + .word 0x6dc22f21 + .word 0x6b03d689 + .word 0x5fc48de0 + .word 0x1138f000 + .word 0xccb58e57 + .word 0xf9c8e200 + .word 0x7ab26e3c + .word 0xc61dcb3e + .word 0x6aefccb0 + .word 0x7a452f05 + .word 0xa5cf0731 + .word 0xa249383f + .word 0x628fe534 + .word 0xcad81710 + .word 0x7f616276 + .word 0x3ce18308 + .word 0xed4857ff + .word 0xd1e5b1d1 + .word 0xc2e84dc2 + .word 0xaa003742 + .word 0xaf637488 + .word 0x831afc48 + .word 0x287a69a0 + .word 0x6e04546e + .word 0x13dffa07 + .word 0x3232fb10 + .word 0xd69e2e09 + .word 0x355d8dc7 + .word 0xef902301 + .word 0x9a89ac15 + .word 0x967dc900 + .word 0x08dc2b1c + .word 0x6b5be690 + .word 0x894b0e02 + .word 0xe26af9af + .word 0xa6fd3b23 + .word 0xfcf213e5 + .word 0x85217608 + .word 0x7fd3be8b + .word 0xa2e757fb + .word 0x3717a341 + .word 0x85ee426d + .word 0x394bb856 + .word 0x12ac98c3 + .word 0xec7d4ab5 + .word 0x721b6989 + .word 0x30e36360 + .word 0xaa018403 + .word 0x9ee61196 + .word 0xa8697adc + .word 0x51e9d65a + .word 0x11023594 + .word 0xc4c4b36b + .word 0xda80bf7a + .word 0xbd5a645e + .word 0x18cea918 + .word 0xa723dda8 + .word 0x0126c05e + .word 0x2962d48a + .word 0xd5f7d312 + .word 0xb8947041 + .word 0x7c1e2e9a + .word 0x945eeac3 + .word 0x7110fb1c + .word 0xa7bc72cc + .word 0xdf47dfbb + .word 0x09a1c6c8 + .word 0xc2e41061 + .word 0 + + +# ---------------------------------------------------------- +# The following is the main program. You may not change this. +# You may only add your subroutines AFTER the "infinite end loop" instruction here. +# You MUST have two subroutines named "codgen" and "decode". +# BOTH must adhere to our calling conventions; +# both MUST preserve all registers except v-regs and t-regs; +# we are going to TEST for this when we run your code. +# ---------------------------------------------------------- + + + .text +main: + addi t0, t1, 0 + la t0, test_word + li t1, 0xFFFFFFFF + sw t1, 0(t0) + sw t1, 4(t0) + sw t1, 8(t0) + sw t1, 12(t0) + li t0, 0x500000F4 # address should be outide of memview range + sw t1, 0(t0) + sw t1, 4(t0) + sw t1, 8(t0) + sw t1, 12(t0) + li s0, 0x0e0657c1 # initialize "seed" + la s1, seed # initialize "seed" + sw s0, 0(s1) + la a0, coded # address of start of coded words + la a1, plain # address of start of decoded bytes + jal ra, codgen + jal ra, codgen + jal ra, codgen + jal ra, codgen + jal ra, codgen + jal ra, codgen + jal ra, decode # outer call to recursive "decode" +end: + j end # infinite loop; plaintext now in "plain". + + +# ---------------------------------------------------------- +# Group 1's assembly code for Function CodGen : +# ---------------------------------------------------------- -start: - lw x0, 0(x0) - sw x1, 0(x1) -l: beq zero, zero, l + # your activation record diagram here. -.section .data -a: .byte 0,1,2,3 -b: .word 0,1,2,3 +# Group 1's Codeword Generator Subroutine (pseudocode) +# (remember: "seed" is a global variable, UNSIGNED INTEGER; +# you may implement local variables in registers or on the stack; +# result returned in v0; preserve all except t regs) +# +# FUNCTION codgen(): UNSIGNED INTEGER; +# LOCAL SIGNED INTEGER n; +# LOCAL UNSIGNED INTEGER x, y; +# BEGIN +# n := [count the number of 0's in word "seed"]; +# x := [rotate "seed" left by 30 bits]; +# y := [shift "seed" right-ARITHMETIC by 6 bits]; +# seed := x XOR y XOR n; +# RETURN( seed XOR 0x464b713e ); +# END; +# +# hint: if "seed" is initialized to 0x3e944b9f, +# the first five calls will generate these values: +# 0x891432f9, 0x4aa1dccc, 0xc54270fa, 0x9885155f, 0xce83d1b8, ... +# your code is to be written farther down (see comment below). + +#t1 = n +#t2 = x +#t3 = y +codgen: + la s1, seed + lw s0, 0(s1) + li t0, 1 + li t1, 0 +loop: + beq t0, x0, continue + and t2, t0, s0 + bne t2, x0, skip + addi t1, t1, 1 +skip: + sll t0, t0, 1 + jal x0, loop +continue: + slli t2, s0, 30 + srli t3, s0, 2 + or t2, t2, t3 #rotate + srai t3, s0, 6 #shift + addi s0, t2, 0 + xor s0, s0, t3 + xor s0, s0, t1 + sw s0, 0(s1) #update seed + jalr x0, ra + + + + + + + +# ---------------------------------------------------------- +# Group 1's assembly code for Function DeCode : +# ---------------------------------------------------------- + + # your activation record diagram here. + +decode: # your code here. + + +# end of file. diff --git a/riscv/examples/riscv.rs b/riscv/examples/riscv.rs index 676fe2a8..d3c1effe 100644 --- a/riscv/examples/riscv.rs +++ b/riscv/examples/riscv.rs @@ -4,12 +4,7 @@ use fern; use riscv::components::*; use riscv_elf_parse; use std::{ - cell::RefCell, - collections::{BTreeMap, HashMap}, - fs, - path::PathBuf, - process::Command, - rc::Rc, + cell::RefCell, collections::BTreeMap, fs, ops::Range, path::PathBuf, process::Command, rc::Rc, }; use syncrim::{ common::{ComponentStore, Input}, @@ -50,7 +45,16 @@ fn main() { println!("{}", memory); let mut instr_mem = BTreeMap::new(); - let mut data_mem = HashMap::new(); + let mut data_mem = BTreeMap::new(); + + //init data memory with 0's + let range = Range { + start: 0x5000_0000u32, + end: 0x5000_0500u32, + }; + for address in range.clone() { + data_mem.insert(address as usize, 0); + } for element in memory.bytes { if element.0 < 0x5000_0000 { instr_mem.insert(element.0, element.1); @@ -58,6 +62,7 @@ fn main() { data_mem.insert(element.0, element.1); } } + let cs = ComponentStore { store: vec![ Add::rc_new( @@ -137,7 +142,6 @@ fn main() { id: "instr_mem".to_string(), pos: (180.0, 400.0), pc: Input::new("reg", "out"), - // fake instructions just to show the relation between input address and instruction bytes: instr_mem, }), Rc::new(Decoder { @@ -186,6 +190,7 @@ fn main() { Input::new("decoder", "data_se"), Input::new("decoder", "data_mem_size"), data_mem, + range, ), Constant::rc_new("zero_c", (680.0, 150.0), 0), Mux::rc_new( @@ -252,14 +257,15 @@ fn fern_setup_riscv() { }) // Add blanket level filter - // .level(log::LevelFilter::Debug); - .level(log::LevelFilter::Warn); + .level_for( + "syncrim::gui_vizia::components::mem", + log::LevelFilter::Trace, + ) + .level(log::LevelFilter::Error); // - and per-module overrides #[cfg(feature = "gui-vizia")] - let f = f - .level_for("syncrim::components::mem", LevelFilter::Trace) - .level_for("riscv::components::instr_mem", LevelFilter::Trace); - //.level_for("riscv", LevelFilter::Trace); + let f = f.level_for("riscv::components::instr_mem", LevelFilter::Trace); f // Output to stdout, files, and other Dispatch configurations diff --git a/riscv/src/components/alu.rs b/riscv/src/components/alu.rs index 980b9890..162c7a80 100644 --- a/riscv/src/components/alu.rs +++ b/riscv/src/components/alu.rs @@ -127,7 +127,7 @@ impl Component for ALU { } //BGEU _ => {} } - trace!("ALU result_o:{}", result_o); + trace!("ALU result_o:{:08x}", result_o); simulator.set_out_value(&self.id, "result_o", result_o); Ok(()) } diff --git a/riscv/src/components/instr_mem.rs b/riscv/src/components/instr_mem.rs index db509159..eb5d74a6 100644 --- a/riscv/src/components/instr_mem.rs +++ b/riscv/src/components/instr_mem.rs @@ -1,4 +1,5 @@ -use std::collections::BTreeMap; +use asm_riscv::{self}; +use std::{collections::BTreeMap, panic}; use log::trace; use serde::{Deserialize, Serialize}; @@ -36,7 +37,12 @@ impl Component for InstrMem { | (*self.bytes.get(&((pc + 1) as usize)).unwrap() as u32) << 16 | (*self.bytes.get(&((pc + 2) as usize)).unwrap() as u32) << 8 | (*self.bytes.get(&((pc + 3) as usize)).unwrap() as u32); - trace!("instruction: 0x{:08x}", instr); + //the asm_riscv crate incorrectly panics when trying from instead of + //returning Err, catch it and handle instead + let instruction_fmt = + panic::catch_unwind(|| format!("{:?}", asm_riscv::I::try_from(instr))) + .unwrap_or_else(|_| format!("Unknown instruction")); + trace!("instruction: {}", instruction_fmt); trace!("pc:0x{:08x}", pc); // set output simulator.set_out_value(&self.id, "instruction", instr); diff --git a/src/components/mem.rs b/src/components/mem.rs index 8397ef80..96419d36 100644 --- a/src/components/mem.rs +++ b/src/components/mem.rs @@ -6,7 +6,9 @@ use log::*; use num_enum::IntoPrimitive; use num_enum::TryFromPrimitive; use serde::{Deserialize, Serialize}; -use std::{cell::RefCell, collections::HashMap, convert::TryFrom, rc::Rc}; +use std::ops::Deref; +use std::ops::Range; +use std::{cell::RefCell, collections::BTreeMap, convert::TryFrom, rc::Rc}; #[derive(Serialize, Deserialize)] pub struct Mem { @@ -27,6 +29,7 @@ pub struct Mem { // memory pub(crate) memory: Memory, + pub(crate) range: Range, // later history... tbd } @@ -43,7 +46,8 @@ impl Mem { ctrl: Input, sext: Input, size: Input, - memory: HashMap, + memory: BTreeMap, + range: Range, ) -> Self { Mem { id: id.to_string(), @@ -57,6 +61,7 @@ impl Mem { sext, size, memory: Memory::new(memory), + range, } } @@ -72,19 +77,15 @@ impl Mem { ctrl: Input, sext: Input, size: Input, + range: Range, ) -> Rc { + let mut mem = BTreeMap::new(); + //fill the defined memory range with zeroes + for i in range.clone() { + mem.insert(i as usize, 0u8); + } Rc::new(Mem::new( - id, - pos, - width, - height, - big_endian, - data, - addr, - ctrl, - sext, - size, - HashMap::new(), + id, pos, width, height, big_endian, data, addr, ctrl, sext, size, mem, range, )) } @@ -100,30 +101,27 @@ impl Mem { ctrl: Input, sext: Input, size: Input, - memory: HashMap, + memory: BTreeMap, + range: Range, ) -> Rc { Rc::new(Mem::new( - id, pos, width, height, big_endian, data, addr, ctrl, sext, size, memory, + id, pos, width, height, big_endian, data, addr, ctrl, sext, size, memory, range, )) } } -#[derive(Serialize, Deserialize, Debug)] -pub struct Memory { - bytes: RefCell>, -} +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Memory(pub Rc>>); impl Default for Memory { fn default() -> Self { - Self::new(HashMap::new()) + Self::new(BTreeMap::new()) } } impl Memory { - pub fn new(data: HashMap) -> Self { - Memory { - bytes: RefCell::new(data), - } + pub fn new(data: BTreeMap) -> Self { + Memory(Rc::new(RefCell::new(data))) } fn align(&self, addr: usize, size: usize) -> SignalValue { @@ -132,7 +130,7 @@ impl Memory { fn read(&self, addr: usize, size: usize, sign: bool, big_endian: bool) -> SignalValue { let data: Vec = (0..size) - .map(|i| *self.bytes.borrow().get(&(addr + i)).unwrap_or(&0)) + .map(|i| *self.0.borrow().get(&(addr + i)).unwrap_or(&0)) .collect(); let data = data.as_slice(); @@ -203,7 +201,7 @@ impl Memory { match size { 1 => { trace!("write byte"); - self.bytes.borrow_mut().insert(addr, data as u8); + self.0.borrow_mut().insert(addr, data as u8); } 2 => { if big_endian { @@ -213,7 +211,7 @@ impl Memory { .iter() .enumerate() .for_each(|(i, bytes)| { - self.bytes.borrow_mut().insert(addr + i, *bytes); + self.0.borrow_mut().insert(addr + i, *bytes); }) } else { trace!("write half word le"); @@ -222,7 +220,7 @@ impl Memory { .iter() .enumerate() .for_each(|(i, bytes)| { - self.bytes.borrow_mut().insert(addr + i, *bytes); + self.0.borrow_mut().insert(addr + i, *bytes); }) } } @@ -234,7 +232,7 @@ impl Memory { .iter() .enumerate() .for_each(|(i, bytes)| { - self.bytes.borrow_mut().insert(addr + i, *bytes); + self.0.borrow_mut().insert(addr + i, *bytes); }) } else { trace!("write word le"); @@ -242,7 +240,7 @@ impl Memory { .iter() .enumerate() .for_each(|(i, bytes)| { - self.bytes.borrow_mut().insert(addr + i, *bytes); + self.0.borrow_mut().insert(addr + i, *bytes); }) } } @@ -330,11 +328,32 @@ impl Component for Mem { } } - trace!("memory {:?}", self.memory); + for (idx, i) in self.memory.0.borrow().iter().enumerate() { + if i.0 % 4 == 0 && idx < 40 { + //only print 40 bytes so the trace isn't busy + trace!( + "0x{:08x} : 0x{:02x}{:02x}{:02x}{:02x}", + i.0, + self.memory.0.borrow().get(i.0).unwrap_or(&0u8), + self.memory.0.borrow().get(&(i.0 + 1)).unwrap_or(&0u8), + self.memory.0.borrow().get(&(i.0 + 2)).unwrap_or(&0u8), + self.memory.0.borrow().get(&(i.0 + 3)).unwrap_or(&0u8), + ) + } + } + Ok(()) } } +impl Deref for Memory { + type Target = RefCell>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + #[cfg(test)] mod test { use super::*; @@ -368,8 +387,10 @@ mod test { sext: Input::new("sign", "out"), // memory - memory: Memory { - bytes: RefCell::new(HashMap::new()), + memory: Memory(Rc::new(RefCell::new(BTreeMap::new()))), + range: Range { + start: 0u32, + end: 1u32, }, }), ], @@ -548,10 +569,12 @@ mod test { sext: Input::new("sign", "out"), // memory - memory: Memory { - bytes: RefCell::new(HashMap::new()), - }, + memory: Memory(Rc::new(RefCell::new(BTreeMap::new()))), // later history... tbd + range: Range { + start: 0u32, + end: 1u32, + }, }), ], }; diff --git a/src/gui_vizia/components/mem.rs b/src/gui_vizia/components/mem.rs index eeb8a52f..1d443380 100644 --- a/src/gui_vizia/components/mem.rs +++ b/src/gui_vizia/components/mem.rs @@ -1,6 +1,9 @@ +use std::ops::Range; + use crate::{ - components::Mem, - gui_vizia::{ViziaComponent, V}, + common::Simulator, + components::{Mem, Memory}, + gui_vizia::{GuiData, ViziaComponent, V}, }; use log::*; use vizia::prelude::*; @@ -12,7 +15,6 @@ impl ViziaComponent for Mem { V::new(cx, self, |cx| { trace!("---- Create Mem View "); Label::new(cx, "DataMemory") - .hoverable(false) .left(Pixels(10.0)) .top(Pixels(10.0)) .hoverable(false) @@ -23,4 +25,148 @@ impl ViziaComponent for Mem { .height(Pixels(self.height)) .background_color(Color::lightgrey()) } + + fn left_view(&self, cx: &mut Context) { + trace!("---- Create Left Mem View"); + //We initialize data_slice with the initial state of the memory. + //from now on, data_slice only gets updated over + //the relevant (visible) data interval, and when needed (so only on clock) + //so as to not trigger unnecessary redraws. + let data_slice = { + let mut data_slice = vec![]; + let mem = self.memory.clone(); + trace!("range {:x?}", self.range); + for idx in (self.range.start as usize..self.range.end as usize).step_by(4) { + trace!("idx {:x?}", idx); + + data_slice.push(format!( + "0x{:08x}: {:02x}{:02x}{:02x}{:02x}", + self.range.start as usize + idx * 4, + mem.0.borrow().get(&idx).copied().unwrap_or(0u8), + mem.0.borrow().get(&(idx + 1)).copied().unwrap_or(0u8), + mem.0.borrow().get(&(idx + 2)).copied().unwrap_or(0u8), + mem.0.borrow().get(&(idx + 3)).copied().unwrap_or(0u8), + )); + } + data_slice + }; + let view = View::build( + DataMemView { + data: self.memory.clone(), + start: self.range.start as usize, + data_slice, + //we may init to 0 range, once view opens this will be updated. + slice_range: Range { start: 0, end: 0 }, + }, + cx, + |cx| { + Label::new(cx, "Data Memory") + .left(Pixels(10.0)) + .top(Pixels(10.0)); + + VirtualList::new(cx, DataMemView::data_slice, 20.0, |cx, _, item| { + HStack::new(cx, |cx| { + Label::new(cx, item); + }) + .child_left(Pixels(10.0)) + }) + .on_change(|cx, range| { + cx.emit(DataEvent::UpdateScroll(range)); + }); + }, + ) + .entity(); + Binding::new( + cx, + GuiData::simulator.then(Simulator::cycle), + move |cx, _| cx.emit_to(view, DataEvent::UpdateClock), + ); + } +} + +#[derive(Lens, Clone)] +pub struct DataMemView { + data: Memory, + start: usize, + data_slice: Vec, + slice_range: Range, +} + +pub enum DataEvent { + UpdateClock, + UpdateScroll(Range), + UpdateView(Range), +} + +impl View for DataMemView { + fn element(&self) -> Option<&'static str> { + Some("MemView") + } + fn event(&mut self, cx: &mut EventContext, event: &mut Event) { + event.map(|event, _| match event { + DataEvent::UpdateView(range) => { + for idx in range.clone() { + if let Some(data_fmt) = self.data_slice.get_mut(idx) { + *data_fmt = format!( + "0x{:08x}: 0x{:02x}{:02x}{:02x}{:02x}", + idx * 4 + self.start, + self.data + .0 + .borrow() + .get(&(self.start + idx * 4)) + .copied() + .unwrap_or(0u8), + self.data + .0 + .borrow() + .get(&(self.start + idx * 4 + 1)) + .copied() + .unwrap_or(0u8), + self.data + .0 + .borrow() + .get(&(self.start + idx * 4 + 2)) + .copied() + .unwrap_or(0u8), + self.data + .0 + .borrow() + .get(&(self.start + idx * 4 + 3)) + .copied() + .unwrap_or(0u8), + ); + } else { + // Why do we end up here, seems wrong + panic!("Internal error, lookup should always succeed.") + } + } + } + DataEvent::UpdateClock => cx.emit(DataEvent::UpdateView(self.slice_range.clone())), //update the entire view on clock. + DataEvent::UpdateScroll(new_range) => { + //calculate the "delta" between the view before and after scroll, update that. + let old_range = self.slice_range.clone(); + self.slice_range = new_range.clone(); + let dirty_range_start = if new_range.start < old_range.start { + new_range.start + } else if new_range.start < old_range.end { + old_range.end + } else { + new_range.start + }; + let dirty_range_end = if new_range.end < old_range.start { + new_range.end + } else if new_range.end < old_range.end { + old_range.start + } else { + new_range.end + }; + let dirty_range = Range { + start: dirty_range_start, + end: dirty_range_end, + }; + + cx.emit(DataEvent::UpdateView(dirty_range)) + } + }) + } } diff --git a/src/gui_vizia/components/mux.rs b/src/gui_vizia/components/mux.rs index d5f169ce..4821c6e6 100644 --- a/src/gui_vizia/components/mux.rs +++ b/src/gui_vizia/components/mux.rs @@ -41,7 +41,7 @@ impl View for MuxView { fn draw(&self, cx: &mut DrawContext<'_>, canvas: &mut Canvas) { let bounds = cx.bounds(); let scale = cx.scale_factor(); - // trace!("Mux draw {:?}", bounds); + trace!("Mux draw {:?}", bounds); let mut path = Path::new(); let mut paint = Paint::color(vizia::vg::Color::rgbf(0.0, 0.0, 0.0));