diff --git a/src/bitarr.rs b/src/bitarr.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4a1b96243c38818ab3d9a6bdc2e39ecfc1bd803f
--- /dev/null
+++ b/src/bitarr.rs
@@ -0,0 +1,124 @@
+use std::cell::Cell;
+use std::convert::TryFrom;
+use std::convert::{From, Into};
+use std::fmt;
+use std::ops::{BitAnd, BitOr, Deref, DerefMut, Index, Range};
+use std::string::String;
+
+#[derive(Debug, PartialEq, Clone)]
+pub struct BitArr<const N: usize>(pub [bool; N]);
+
+// operations on BitArr
+impl<const N: usize> BitArr<N> {
+    pub fn sign_zero_ext<const M: usize>(&self, b: bool) -> BitArr<M> {
+        let msb = if b { self.0[N - 1] } else { false };
+        let mut res = [msb; M];
+        res[0..N].copy_from_slice(&self.0);
+
+        BitArr(res)
+    }
+
+    pub fn sign_ext<const M: usize>(&self) -> BitArr<M> {
+        self.sign_zero_ext(true)
+    }
+
+    pub fn zero_ext<const M: usize>(&self) -> BitArr<M> {
+        self.sign_zero_ext(false)
+    }
+}
+
+impl<const N: usize> DerefMut for BitArr<N> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.0
+    }
+}
+
+impl<const N: usize> Deref for BitArr<N> {
+    type Target = [bool; N];
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<const N: usize> fmt::Binary for BitArr<N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut s = String::new();
+        for i in self.0.iter().rev() {
+            s.push(if *i { '1' } else { '0' });
+        }
+        write!(f, "{}", s)
+    }
+}
+
+// Convert a u8 to BitArr<N>
+// panic: N is too small to fit all true bits of u8
+// if N is larger than 8, other bits set zero
+impl<const N: usize> From<u8> for BitArr<N> {
+    fn from(u: u8) -> Self {
+        let mut bs = [false; N];
+        for i in 0..8 {
+            let b = u & (1 << i);
+            if b != 0 {
+                bs[i] = true
+            }
+        }
+        BitArr(bs)
+    }
+}
+
+// Convert a BitArr<N> to u8
+// panic: if N > 8
+// if N <= 8 upper bits are set 0
+impl<const N: usize> From<BitArr<N>> for u8 {
+    fn from(bs: BitArr<N>) -> Self {
+        assert!(N <= 8);
+        let mut b = 0u8;
+        for i in 0..N {
+            if bs[i] {
+                b |= 1 << i
+            }
+        }
+        b
+    }
+}
+
+// operations on bit array
+
+impl<const N: usize> BitAnd for &BitArr<N> {
+    type Output = BitArr<N>;
+
+    // rhs is the "right-hand side" of the expression `a & b`
+    fn bitand(self, rhs: Self) -> Self::Output {
+        let mut bs = [false; N];
+        for i in 0..self.0.len() {
+            bs[i] = self.0[i] & rhs.0[i]
+        }
+        BitArr(bs)
+    }
+}
+
+impl<const N: usize> BitOr for &BitArr<N> {
+    type Output = BitArr<N>;
+
+    // rhs is the "right-hand side" of the expression `a & b`
+    fn bitor(self, rhs: Self) -> Self::Output {
+        let mut bs = [false; N];
+        for i in 0..self.0.len() {
+            bs[i] = self.0[i] | rhs.0[i]
+        }
+        BitArr(bs)
+    }
+}
+
+#[test]
+mod test {
+    #[test]
+    fn extensions() {
+        let a: BitArr<2> = 0b10u8.into();
+        let ze: BitArr<4> = a.zero_ext();
+        let se: BitArr<4> = a.sign_ext();
+        assert!(ze == 0b0010u8.into());
+        assert!(se == 0b1110u8.into());
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 6a790878f555e85d100d0d95daeaef095b7d6725..6278f9e1ed70ec656f4b327b3d70d74f5e6d1174 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,7 @@
+mod bitarr;
 mod signal;
+
+pub use bitarr::*;
 pub use signal::*;
 
 // pub struct Component {
diff --git a/src/main.rs b/src/main.rs
index 5068a7f5b5f73c507326a2c1d57abcf8c8290ee5..7f4e78c28e3fe1618fe7c20c900cec78565205ec 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -70,8 +70,8 @@ use rsim::*;
 // two input mux
 struct Mux<'a, const N: usize> {
     ins: (Signal<'a, N>, Signal<'a, N>),
-    sel: &'a Signal<'a, 1>,
-    out: &'a Signal<'a, N>,
+    sel: Signal<'a, 1>,
+    out: Signal<'a, N>,
 }
 
 impl<'a, const N: usize> Eval for Mux<'a, N> {
@@ -83,6 +83,64 @@ impl<'a, const N: usize> Eval for Mux<'a, N> {
     }
 }
 
+// zero extend
+struct ZeroExt<'a, const N: usize, const M: usize> {
+    ins: Signal<'a, N>,
+    out: Signal<'a, M>,
+}
+
+impl<'a, const N: usize, const M: usize> Eval for ZeroExt<'a, N, M> {
+    fn eval(&self) -> () {
+        let mut res = BitArr([false; M]);
+        res[0..N].clone_from_slice(&*self.ins.r());
+
+        self.out.w(res);
+    }
+}
+
+
+
+#[test]
+fn test_zero_ext() {
+    let mut ins: BitArr<2> = 0b10u8.into();
+    println!("ins {:b}", ins);
+    let mut out: BitArr<4> = 0.into();
+    let ze = ZeroExt {
+        ins: Signal::new(&mut ins),
+        out: Signal::new(&mut out),
+    };
+    ze.eval();
+    println!("ze.out {:b}", ze.out);
+}
+
+// sign extend
+struct SignExt<'a, const N: usize, const M: usize> {
+    ins: Signal<'a, N>,
+    out: Signal<'a, M>,
+}
+
+impl<'a, const N: usize, const M: usize> Eval for SignExt<'a, N, M> {
+    fn eval(&self) -> () {
+        let mut res = BitArr([self.ins.r()[N - 1]; M]);
+        res[0..N].clone_from_slice(&*self.ins.r());
+
+        self.out.w(res);
+    }
+}
+
+#[test]
+fn test_sign_ext() {
+    let mut ins: BitArr<2> = 0b10u8.into();
+    println!("ins {:b}", ins);
+    let mut out: BitArr<4> = 0.into();
+    let se = SignExt {
+        ins: Signal::new(&mut ins),
+        out: Signal::new(&mut out),
+    };
+    se.eval();
+    println!("ze.out {:b}", se.out);
+}
+
 fn main() {
     let mut in1: BitArr<2> = 0b10u8.into(); // [false, true];
     println!("{:?}", in1);
@@ -97,56 +155,34 @@ fn main() {
 
     let mut sel = [false];
     let sel = Signal::new(&mut sel);
+
     let mut out = [false, false];
+    let out = Signal::new(&mut out);
 
-    let out = &Signal::new(&mut out);
-    let out0: Signal<1> = out.view(0, 1);
-    let out1: Signal<1> = out.view(1, 2);
+    // let out0: Signal<1> = out.view(0, 1);
+    // let out1: Signal<1> = out.view(1, 2);
 
     let m = Mux {
         ins: (Signal::new(&mut in1), Signal::new(&mut in2)),
-        sel: &sel,
+        sel: sel,
         out,
     };
 
     println!("m.out {:b}", m.out);
     m.eval();
-    sel.w(BitArr([false]));
+    m.sel.w(BitArr([false]));
     m.eval();
     println!("m.out {:b}", m.out);
-    sel[0].set(false);
-    sel.w(BitArr([false]));
-    // sel.store_slice(&[false]);
+    m.sel[0].set(false);
+    m.sel.w(BitArr([false]));
+
     m.eval();
     println!("m.out {:?}", m.out);
-    println!("out0 {:b}", &out0);
-    println!("out1 {:b}", &out1);
+    // println!("out0 {:b}", out0);
+    // println!("out1 {:b}", out1);
     let p = &m.out[0..1];
     let m: Signal<2> = m.out[0..2].into();
 }
-// #[derive(Debug)]
-// struct Mux<'a, const I: usize, const S: usize, const N: usize> {
-//     inputs: [&'a Signal<N>; I],
-//     sel: &'a Signal<S>,
-//     output: Signal<N>,
-// }
-
-// impl<'a, const I: usize, const S: usize, const N: usize> Eval for Mux<'a, I, S, N> {
-//     fn eval(&self) {
-//         let s: u8 = self.sel.clone().into();
-//         println!("s {}", s);
-
-//         let o = self.inputs[s as usize];
-
-//         self.output.store.set(o.store.get())
-//     }
-// }
-
-// impl<'a, const I: usize, const S: usize, const N: usize> fmt::Binary for Mux<'a, I, S, N> {
-//     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-//         fmt::Binary::fmt(&self.output, f)
-//     }
-// }
 
 // fn main() {
 //     let s1: Signal<8> = 0b10101u8.into();
@@ -178,24 +214,6 @@ fn main() {
 
 // }
 
-// #[derive(Debug)]
-// struct AndIn<'a> {
-//     a: &'a Signal,
-//     b: &'a Signal,
-// }
-
-// #[derive(Debug)]
-// struct And<'a> {
-//     inputs: AndIn<'a>,
-//     output: Signal,
-// }
-
-// impl<'a> Eval for And<'a> {
-//     fn eval(&mut self) {
-//         self.output = (self.inputs.a & self.inputs.b).clone()
-//     }
-// }
-
 // fn main() {
 //     let a: Signal = 1u8.into();
 //     let b: Signal = 2u8.into();
diff --git a/src/signal.rs b/src/signal.rs
index d739ef99776684da6295bda40f9eeee497a8681a..cbac7f5c00f8d22b76f479cafd4e4b20785751b4 100644
--- a/src/signal.rs
+++ b/src/signal.rs
@@ -5,92 +5,7 @@ use std::fmt;
 use std::ops::{BitAnd, BitOr, Deref, DerefMut, Index, Range};
 use std::string::String;
 
-#[derive(Debug, PartialEq, Clone)]
-pub struct BitArr<const N: usize>(pub [bool; N]);
-
-impl<const N: usize> DerefMut for BitArr<N> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.0
-    }
-}
-
-impl<const N: usize> Deref for BitArr<N> {
-    type Target = [bool; N];
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl<const N: usize> fmt::Binary for BitArr<N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut s = String::new();
-        for i in self.0.iter().rev() {
-            s.push(if *i { '1' } else { '0' });
-        }
-        write!(f, "{}", s)
-    }
-}
-
-// Convert a u8 to BitArr<N>
-// panic: N is too small to fit all true bits of u8
-// if N is larger than 8, other bits set zero
-impl<const N: usize> From<u8> for BitArr<N> {
-    fn from(u: u8) -> Self {
-        let mut bs = [false; N];
-        for i in 0..8 {
-            let b = u & (1 << i);
-            if b != 0 {
-                bs[i] = true
-            }
-        }
-        BitArr(bs)
-    }
-}
-
-// Convert a BitArr<N> to u8
-// panic: if N > 8
-// if N <= 8 upper bits are set 0
-impl<const N: usize> From<BitArr<N>> for u8 {
-    fn from(bs: BitArr<N>) -> Self {
-        assert!(N <= 8);
-        let mut b = 0u8;
-        for i in 0..N {
-            if bs[i] {
-                b |= 1 << i
-            }
-        }
-        b
-    }
-}
-
-// operations on bit array
-impl<const N: usize> BitAnd for &BitArr<N> {
-    type Output = BitArr<N>;
-
-    // rhs is the "right-hand side" of the expression `a & b`
-    fn bitand(self, rhs: Self) -> Self::Output {
-        let mut bs = [false; N];
-        for i in 0..self.0.len() {
-            bs[i] = self.0[i] & rhs.0[i]
-        }
-        BitArr(bs)
-    }
-}
-
-impl<const N: usize> BitOr for &BitArr<N> {
-    type Output = BitArr<N>;
-
-    // rhs is the "right-hand side" of the expression `a & b`
-    fn bitor(self, rhs: Self) -> Self::Output {
-        let mut bs = [false; N];
-        for i in 0..self.0.len() {
-            bs[i] = self.0[i] | rhs.0[i]
-        }
-        BitArr(bs)
-    }
-}
-
+use crate::bitarr::*;
 // representation of stateful signal
 #[derive(Debug, PartialEq, Clone)]
 
@@ -124,11 +39,11 @@ impl<'a, const N: usize> Signal<'a, N> {
     }
 
     // not sure if we should support this
-    // pub fn store_slice(&self, a: &[bool]) {
-    //     for (i, v) in self.store.iter().enumerate() {
-    //         v.set(a[i])
-    //     }
-    // }
+    pub fn store_slice(&self, a: &[bool]) {
+        for (i, v) in self.store.iter().enumerate() {
+            v.set(a[i])
+        }
+    }
 
     // create a view of the signal
     // for now this view provides both reading and writing
@@ -166,7 +81,7 @@ impl<'a, const N: usize> Deref for Signal<'a, N> {
 
 // prints the value of a signal
 // perhaps we should enforce reading the signal into a bit array first
-impl<'a, const N: usize> fmt::Binary for &Signal<'a, N> {
+impl<'a, const N: usize> fmt::Binary for Signal<'a, N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut s = String::new();
         for i in self.store.iter().rev() {
@@ -187,72 +102,6 @@ impl<'a, const N: usize> fmt::Binary for &Signal<'a, N> {
 //     }
 // }
 
-// // operations on signal
-// impl<'a, const N: usize> BitAnd for Signal<'a, N> {
-//     type Output = Signal<'a, N>;
-
-//     // rhs is the "right-hand side" of the expression `a & b`
-//     fn bitand(self, rhs: Self) -> Self::Output {
-
-//         // let mut bs = [false; N];
-//         // let a = self.store.get();
-//         // let b = rhs.store.get();
-//         // for i in 0..self.store.get().len() {
-//         //     bs[i] = a[i] & b[i]
-//         // }
-//         // Signal {
-//         //     store: Cell::new(bs),
-//         // }
-//     }
-// }
-
-// impl<const N: usize> BitOr for &Signal<N> {
-//     type Output = Signal<N>;
-
-//     // rhs is the "right-hand side" of the expression `a & b`
-//     fn bitor(self, rhs: Self) -> Self::Output {
-//         let mut bs: Signal<N> = Signal::new();
-//         for i in 0..self.store.len() {
-//             bs.store[i] = self.store[i] | rhs.store[i]
-//         }
-//         bs
-//     }
-// }
-
-// impl<const N: usize> From<Signal<N>> for u8 {
-//     fn from(s: Signal<N>) -> u8 {
-//         // check that it fits u8
-//         assert!(N < 8);
-//         let mut u = 0;
-//         let a = s.store.get();
-
-//         for i in 0..N {
-//             u |= if a[i] { 1 << i } else { 0 }
-//         }
-//         u
-//     }
-// }
-
-// impl From<u32> for Signal {
-//     fn from(u: u32) -> Self {
-//         let mut bs = Signal::new();
-//         for i in 0..32 {
-//             bs.push(u & (1 << i) != 0)
-//         }
-//         bs
-//     }
-// }
-
-// impl From<Signal> for u32 {
-//     fn from(b: Signal) -> u32 {
-//         let mut u = 0;
-//         for (n, b) in b.0.iter().enumerate() {
-//             u |= if *b { 1 << n } else { 0 }
-//         }
-//         u
-//     }
-// }
-
 // #[test]
 // fn test_partial_eq() {
 //     let b: Signal = 12345u32.into();