···1212// You should have received a copy of the GNU General Public License along with
1313// this program. If not, see <https://www.gnu.org/licenses/>.
1414//
1515+mod ops;
1616+mod reg;
1717+mod universal_machine;
1818+1519use std::{path::Path, time::Instant};
1616-use um::Um;
2020+use universal_machine::Um;
17211822fn main() {
1923 let mut program = Vec::new();
+2-330
src/lib.rs
···1212// You should have received a copy of the GNU General Public License along with
1313// this program. If not, see <https://www.gnu.org/licenses/>.
1414//
1515-use smallvec::SmallVec;
1616-use std::io::{Read, Write};
17151816#[cfg(feature = "asm")]
1917pub mod asm;
···2119pub mod ops;
2220pub mod reg;
23212424-use ops::Operation;
2525-use reg::{Page, Register};
2626-2727-const SMALLVEC_SIZE: usize = 24;
2828-2929-/// Lossless conversion to `usize`.
3030-///
3131-/// This should only be implemented on types which can be losslessly
3232-/// cast to a `usize`.
3333-trait IntoIndex: Sized + Copy {
3434- fn into_index(self) -> usize;
3535-}
3636-3737-macro_rules! impl_into_index {
3838- ($t:ty) => {
3939- impl IntoIndex for $t {
4040- fn into_index(self) -> usize {
4141- self as usize
4242- }
4343- }
4444- };
4545-}
4646-4747-#[cfg(target_pointer_width = "16")]
4848-compile_error!("16 bit architectures are unsupported");
4949-5050-// usize *may* be 16 bits, so only implement if it is 32 or 64 bits.
5151-#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
5252-impl_into_index!(u32);
5353-5454-#[derive(Default)]
5555-pub struct Um<'a> {
5656- pub program_counter: u32,
5757- registers: Page,
5858- /// Program memory, modelled as a `Vec` of `SmallVec`.
5959- ///
6060- /// Memory allocations greater than `SMALLVEC_SIZE` will incur a memory
6161- /// indirection penalty for every memory access within that block.
6262- memory: Vec<SmallVec<[u32; SMALLVEC_SIZE]>>,
6363- free_blocks: Vec<u32>,
6464- /// Partially decoded operations cache.
6565- ops: Vec<Operation>,
6666- stdin: Option<&'a mut dyn Read>,
6767- stdout: Option<&'a mut dyn Write>,
6868-}
6969-7070-impl<'a> Um<'a> {
7171- /// Initialise a Universal Machine with the specified program scroll.
7272- pub fn new(program: Vec<u32>) -> Self {
7373- let ops = ops::decode(&program);
7474- Self {
7575- memory: vec![program.into()],
7676- ops,
7777- ..Default::default()
7878- }
7979- }
8080-8181- /// Sets the output for the universal machine.
8282- pub fn stdout<T: Write>(mut self, stdout: &'a mut T) -> Self {
8383- self.stdout.replace(stdout);
8484- self
8585- }
8686-8787- /// Sets the input for the universal machine.
8888- pub fn stdin<T: Read>(mut self, stdin: &'a mut T) -> Self {
8989- self.stdin.replace(stdin);
9090- self
9191- }
9292-9393- /// Begins the spin-cycle of the universal machine.
9494- #[inline(never)]
9595- pub fn run(mut self) -> Self {
9696- loop {
9797- // println!(
9898- // "{:?}, pc: {:08x}, r: {:08x?}",
9999- // self.ops[self.program_counter as usize], self.program_counter, self.registers
100100- // );
101101- match self.ops[self.program_counter as usize] {
102102- Operation::ConditionalMove { a, b, c } => self.conditional_move(a, b, c),
103103- Operation::ArrayIndex { a, b, c } => self.array_index(a, b, c),
104104- Operation::ArrayAmendment { a, b, c } => self.array_amendment(a, b, c),
105105- Operation::Addition { a, b, c } => self.addition(a, b, c),
106106- Operation::Multiplication { a, b, c } => self.multiplication(a, b, c),
107107- Operation::Division { a, b, c } => self.division(a, b, c),
108108- Operation::NotAnd { a, b, c } => self.not_and(a, b, c),
109109- Operation::Halt => break,
110110- Operation::Allocation { b, c } => self.allocation(b, c),
111111- Operation::Abandonment { c } => self.abandonment(c),
112112- Operation::Output { c } => self.output(c),
113113- Operation::Input { c } => self.input(c),
114114- Operation::LoadProgram { b, c } => {
115115- self.load_program(b, c);
116116- continue;
117117- }
118118- Operation::Orthography { a, value } => self.orthography(a, value),
119119- Operation::IllegalInstruction => self.illegal_instruction(),
120120- }
121121- self.program_counter += 1;
122122- }
123123-124124- self
125125- }
126126-127127- // Un-commenting step() slows down the sandmark benchmark by ~3-5 seconds, even
128128- // though it has *no* interaction with the code path in Um::run().
129129- //
130130- // /// Steps one instruction.
131131- // #[inline(never)]
132132- // pub fn step(&mut self) -> bool {
133133- // match self.ops[self.program_counter as usize] {
134134- // Operation::ConditionalMove { a, b, c } => self.conditional_move(a, b, c),
135135- // Operation::ArrayIndex { a, b, c } => self.array_index(a, b, c),
136136- // Operation::ArrayAmendment { a, b, c } => self.array_amendment(a, b, c),
137137- // Operation::Addition { a, b, c } => self.addition(a, b, c),
138138- // Operation::Multiplication { a, b, c } => self.multiplication(a, b, c),
139139- // Operation::Division { a, b, c } => self.division(a, b, c),
140140- // Operation::NotAnd { a, b, c } => self.not_and(a, b, c),
141141- // Operation::Halt => return false,
142142- // Operation::Allocation { b, c } => self.allocation(b, c),
143143- // Operation::Abandonment { c } => self.abandonment(c),
144144- // Operation::Output { c } => self.output(c),
145145- // Operation::Input { c } => self.input(c),
146146- // Operation::LoadProgram { b, c } => {
147147- // self.load_program(b, c);
148148- // return true;
149149- // }
150150- // Operation::Orthography { a, value } => self.orthography(a, value),
151151- // Operation::IllegalInstruction => self.illegal_instruction(),
152152- // }
153153- // self.program_counter += 1;
154154- // true
155155- // }
156156-157157- /// Loads the value from the specified register.
158158- fn load_register(&self, register: Register) -> u32 {
159159- self.registers[register]
160160- }
161161-162162- /// Saves a value to the specified register.
163163- fn save_register(&mut self, register: Register, value: u32) {
164164- self.registers[register] = value;
165165- }
166166-167167- fn conditional_move(&mut self, a: Register, b: Register, c: Register) {
168168- if self.load_register(c) != 0 {
169169- self.save_register(a, self.load_register(b));
170170- }
171171- }
172172-173173- fn array_index(&mut self, a: Register, b: Register, c: Register) {
174174- let block = self.load_register(b);
175175- let offset = self.load_register(c);
176176- self.save_register(a, self.load_memory(block, offset));
177177- }
178178-179179- fn array_amendment(&mut self, a: Register, b: Register, c: Register) {
180180- let block = self.load_register(a);
181181- let offset = self.load_register(b);
182182- let value = self.load_register(c);
183183- self.store_memory(block, offset, value);
184184- }
185185-186186- fn addition(&mut self, a: Register, b: Register, c: Register) {
187187- self.save_register(a, self.load_register(b).wrapping_add(self.load_register(c)));
188188- }
189189-190190- fn multiplication(&mut self, a: Register, b: Register, c: Register) {
191191- self.save_register(a, self.load_register(b).wrapping_mul(self.load_register(c)));
192192- }
193193-194194- fn division(&mut self, a: Register, b: Register, c: Register) {
195195- self.save_register(a, self.load_register(b).wrapping_div(self.load_register(c)));
196196- }
197197-198198- fn not_and(&mut self, a: Register, b: Register, c: Register) {
199199- self.save_register(a, !(self.load_register(b) & self.load_register(c)));
200200- }
201201-202202- fn allocation(&mut self, b: Register, c: Register) {
203203- let length = self.load_register(c);
204204- let index = self.allocate_memory(length);
205205- self.save_register(b, index);
206206- }
207207-208208- fn abandonment(&mut self, c: Register) {
209209- let block = self.load_register(c);
210210- self.free_memory(block);
211211- }
212212-213213- fn output(&mut self, c: Register) {
214214- let value = self.load_register(c);
215215- if let Some(stdout) = self.stdout.as_mut() {
216216- let buffer = [(value & 0xff) as u8];
217217- stdout.write_all(&buffer).unwrap();
218218- }
219219- }
220220-221221- fn input(&mut self, c: Register) {
222222- if let Some(stdin) = self.stdin.as_mut() {
223223- let mut buffer = vec![0];
224224- match stdin.read_exact(&mut buffer) {
225225- Ok(()) => self.save_register(c, buffer[0] as u32),
226226- Err(_) => self.save_register(c, u32::MAX),
227227- }
228228- } else {
229229- self.save_register(c, u32::MAX);
230230- }
231231- }
232232-233233- fn load_program(&mut self, b: Register, c: Register) {
234234- let block = self.load_register(b);
235235-236236- // Source array is always copied to array[0], but there
237237- // is no point copying array[0] to array[0].
238238- if block != 0 {
239239- let duplicated = self.duplicate_memory(block);
240240- let ops = ops::decode(duplicated);
241241- self.ops = ops;
242242- }
243243-244244- self.program_counter = self.load_register(c);
245245- }
246246-247247- fn orthography(&mut self, a: Register, value: u32) {
248248- self.save_register(a, value);
249249- }
250250-251251- #[cold]
252252- #[inline(never)]
253253- fn illegal_instruction(&self) -> ! {
254254- panic!(
255255- "illegal instruction: {:08x}, pc: {:08x}, r: {:08x?}",
256256- self.memory[0][self.program_counter.into_index()],
257257- self.program_counter,
258258- self.registers
259259- )
260260- }
261261-262262- fn load_memory(&self, block: u32, offset: u32) -> u32 {
263263- let block = block.into_index();
264264- let offset = offset.into_index();
265265- assert!(block < self.memory.len() && offset < self.memory[block].len());
266266- self.memory[block][offset]
267267- }
268268-269269- fn store_memory(&mut self, block: u32, offset: u32, value: u32) {
270270- let block = block.into_index();
271271- let offset = offset.into_index();
272272- assert!(block < self.memory.len() && offset < self.memory[block].len());
273273- self.memory[block][offset] = value
274274- }
275275-276276- /// Duplicates a block of memory.
277277- ///
278278- /// The block is copied to the first block of memory.
279279- fn duplicate_memory(&mut self, block: u32) -> &[u32] {
280280- let block = block.into_index();
281281- assert!(block < self.memory.len());
282282- self.memory[0] = self.memory[block].clone();
283283- &self.memory[0]
284284- }
285285-286286- /// Allocates a block of memory of the specified length.
287287- fn allocate_memory(&mut self, length: u32) -> u32 {
288288- if let Some(index) = self.free_blocks.pop() {
289289- self.memory[index.into_index()] = Self::new_block(length.into_index());
290290- index
291291- } else {
292292- self.memory.push(Self::new_block(length.into_index()));
293293- (self.memory.len() - 1) as u32
294294- }
295295- }
2222+mod universal_machine;
29623297297- /// Frees a block of memory.
298298- fn free_memory(&mut self, block: u32) {
299299- assert!(block.into_index() < self.memory.len());
300300- self.free_blocks.push(block);
301301- self.memory[block.into_index()] = Self::new_block(0);
302302- }
303303-304304- /// Creates a new block of memory.
305305- ///
306306- /// The block is initialised with `len` zeroes.
307307- fn new_block(len: usize) -> SmallVec<[u32; SMALLVEC_SIZE]> {
308308- smallvec::smallvec![0; len]
309309- }
310310-}
311311-312312-#[cfg(test)]
313313-mod tests {
314314- use super::*;
315315-316316- #[test]
317317- #[should_panic]
318318- fn empty_program() {
319319- Um::new(vec![]).run();
320320- }
321321-322322- #[test]
323323- fn just_halt() {
324324- Um::new(vec![0x70000000]).run();
325325- }
326326-327327- #[test]
328328- #[cfg(feature = "asm")]
329329- fn hello_world() {
330330- let program = asm::assemble(include_str!("../files/hello-world.asm"));
331331- let mut buffer = Vec::new();
332332- Um::new(program).stdout(&mut buffer).run();
333333- assert_eq!(&buffer, b"Hello, world!\n");
334334- }
335335-336336- #[test]
337337- #[cfg(feature = "asm")]
338338- fn cat() {
339339- let program = asm::assemble(include_str!("../files/cat.asm"));
340340- let input = include_bytes!("lib.rs");
341341-342342- let mut reader = std::io::Cursor::new(input);
343343- let mut buffer = Vec::new();
344344-345345- Um::new(program)
346346- .stdin(&mut reader)
347347- .stdout(&mut buffer)
348348- .run();
349349-350350- assert_eq!(&buffer, &input);
351351- }
352352-}
2424+pub use universal_machine::Um;
+334
src/universal_machine.rs
···11+use std::io::Read;
22+use std::io::Write;
33+44+use smallvec::SmallVec;
55+66+use crate::ops::Operation;
77+use crate::reg::{Page, Register};
88+99+pub(crate) const SMALLVEC_SIZE: usize = 24;
1010+1111+/// Lossless conversion to `usize`.
1212+///
1313+/// This should only be implemented on types which can be losslessly
1414+/// cast to a `usize`.
1515+pub(crate) trait IntoIndex: Sized + Copy {
1616+ fn into_index(self) -> usize;
1717+}
1818+1919+macro_rules! impl_into_index {
2020+ ($t:ty) => {
2121+ impl IntoIndex for $t {
2222+ fn into_index(self) -> usize {
2323+ self as usize
2424+ }
2525+ }
2626+ };
2727+}
2828+2929+#[cfg(target_pointer_width = "16")]
3030+compile_error!("16 bit architectures are unsupported");
3131+3232+// usize *may* be 16 bits, so only implement if it is 32 or 64 bits.
3333+#[cfg(any(target_pointer_width = "64", target_pointer_width = "32"))]
3434+impl_into_index!(u32);
3535+3636+#[derive(Default)]
3737+pub struct Um<'a> {
3838+ pub program_counter: u32,
3939+ pub(crate) registers: Page,
4040+ /// Program memory, modelled as a `Vec` of `SmallVec`.
4141+ ///
4242+ /// Memory allocations greater than `SMALLVEC_SIZE` will incur a memory
4343+ /// indirection penalty for every memory access within that block.
4444+ pub(crate) memory: Vec<SmallVec<[u32; SMALLVEC_SIZE]>>,
4545+ pub(crate) free_blocks: Vec<u32>,
4646+ /// Partially decoded operations cache.
4747+ pub(crate) ops: Vec<Operation>,
4848+ pub(crate) stdin: Option<&'a mut dyn Read>,
4949+ pub(crate) stdout: Option<&'a mut dyn Write>,
5050+}
5151+5252+impl<'a> Um<'a> {
5353+ /// Initialise a Universal Machine with the specified program scroll.
5454+ pub fn new(program: Vec<u32>) -> Self {
5555+ let ops = crate::ops::decode(&program);
5656+ Self {
5757+ memory: vec![program.into()],
5858+ ops,
5959+ ..Default::default()
6060+ }
6161+ }
6262+6363+ /// Sets the output for the universal machine.
6464+ pub fn stdout<T: Write>(mut self, stdout: &'a mut T) -> Self {
6565+ self.stdout.replace(stdout);
6666+ self
6767+ }
6868+6969+ /// Sets the input for the universal machine.
7070+ pub fn stdin<T: Read>(mut self, stdin: &'a mut T) -> Self {
7171+ self.stdin.replace(stdin);
7272+ self
7373+ }
7474+7575+ /// Begins the spin-cycle of the universal machine.
7676+ #[inline(never)]
7777+ pub fn run(mut self) -> Self {
7878+ loop {
7979+ // println!(
8080+ // "{:?}, pc: {:08x}, r: {:08x?}",
8181+ // self.ops[self.program_counter as usize], self.program_counter, self.registers
8282+ // );
8383+ match self.ops[self.program_counter as usize] {
8484+ Operation::ConditionalMove { a, b, c } => self.conditional_move(a, b, c),
8585+ Operation::ArrayIndex { a, b, c } => self.array_index(a, b, c),
8686+ Operation::ArrayAmendment { a, b, c } => self.array_amendment(a, b, c),
8787+ Operation::Addition { a, b, c } => self.addition(a, b, c),
8888+ Operation::Multiplication { a, b, c } => self.multiplication(a, b, c),
8989+ Operation::Division { a, b, c } => self.division(a, b, c),
9090+ Operation::NotAnd { a, b, c } => self.not_and(a, b, c),
9191+ Operation::Halt => break,
9292+ Operation::Allocation { b, c } => self.allocation(b, c),
9393+ Operation::Abandonment { c } => self.abandonment(c),
9494+ Operation::Output { c } => self.output(c),
9595+ Operation::Input { c } => self.input(c),
9696+ Operation::LoadProgram { b, c } => {
9797+ self.load_program(b, c);
9898+ continue;
9999+ }
100100+ Operation::Orthography { a, value } => self.orthography(a, value),
101101+ Operation::IllegalInstruction => self.illegal_instruction(),
102102+ }
103103+ self.program_counter += 1;
104104+ }
105105+106106+ self
107107+ }
108108+109109+ // Un-commenting step() slows down the sandmark benchmark by ~3-5 seconds, even
110110+ // though it has *no* interaction with the code path in Um::run().
111111+ //
112112+ // /// Steps one instruction.
113113+ // #[inline(never)]
114114+ // pub fn step(&mut self) -> bool {
115115+ // match self.ops[self.program_counter as usize] {
116116+ // Operation::ConditionalMove { a, b, c } => self.conditional_move(a, b, c),
117117+ // Operation::ArrayIndex { a, b, c } => self.array_index(a, b, c),
118118+ // Operation::ArrayAmendment { a, b, c } => self.array_amendment(a, b, c),
119119+ // Operation::Addition { a, b, c } => self.addition(a, b, c),
120120+ // Operation::Multiplication { a, b, c } => self.multiplication(a, b, c),
121121+ // Operation::Division { a, b, c } => self.division(a, b, c),
122122+ // Operation::NotAnd { a, b, c } => self.not_and(a, b, c),
123123+ // Operation::Halt => return false,
124124+ // Operation::Allocation { b, c } => self.allocation(b, c),
125125+ // Operation::Abandonment { c } => self.abandonment(c),
126126+ // Operation::Output { c } => self.output(c),
127127+ // Operation::Input { c } => self.input(c),
128128+ // Operation::LoadProgram { b, c } => {
129129+ // self.load_program(b, c);
130130+ // return true;
131131+ // }
132132+ // Operation::Orthography { a, value } => self.orthography(a, value),
133133+ // Operation::IllegalInstruction => self.illegal_instruction(),
134134+ // }
135135+ // self.program_counter += 1;
136136+ // true
137137+ // }
138138+139139+ /// Loads the value from the specified register.
140140+ pub(crate) fn load_register(&self, register: Register) -> u32 {
141141+ self.registers[register]
142142+ }
143143+144144+ /// Saves a value to the specified register.
145145+ pub(crate) fn save_register(&mut self, register: Register, value: u32) {
146146+ self.registers[register] = value;
147147+ }
148148+149149+ pub(crate) fn conditional_move(&mut self, a: Register, b: Register, c: Register) {
150150+ if self.load_register(c) != 0 {
151151+ self.save_register(a, self.load_register(b));
152152+ }
153153+ }
154154+155155+ pub(crate) fn array_index(&mut self, a: Register, b: Register, c: Register) {
156156+ let block = self.load_register(b);
157157+ let offset = self.load_register(c);
158158+ self.save_register(a, self.load_memory(block, offset));
159159+ }
160160+161161+ pub(crate) fn array_amendment(&mut self, a: Register, b: Register, c: Register) {
162162+ let block = self.load_register(a);
163163+ let offset = self.load_register(b);
164164+ let value = self.load_register(c);
165165+ self.store_memory(block, offset, value);
166166+ }
167167+168168+ pub(crate) fn addition(&mut self, a: Register, b: Register, c: Register) {
169169+ self.save_register(a, self.load_register(b).wrapping_add(self.load_register(c)));
170170+ }
171171+172172+ pub(crate) fn multiplication(&mut self, a: Register, b: Register, c: Register) {
173173+ self.save_register(a, self.load_register(b).wrapping_mul(self.load_register(c)));
174174+ }
175175+176176+ pub(crate) fn division(&mut self, a: Register, b: Register, c: Register) {
177177+ self.save_register(a, self.load_register(b).wrapping_div(self.load_register(c)));
178178+ }
179179+180180+ pub(crate) fn not_and(&mut self, a: Register, b: Register, c: Register) {
181181+ self.save_register(a, !(self.load_register(b) & self.load_register(c)));
182182+ }
183183+184184+ pub(crate) fn allocation(&mut self, b: Register, c: Register) {
185185+ let length = self.load_register(c);
186186+ let index = self.allocate_memory(length);
187187+ self.save_register(b, index);
188188+ }
189189+190190+ pub(crate) fn abandonment(&mut self, c: Register) {
191191+ let block = self.load_register(c);
192192+ self.free_memory(block);
193193+ }
194194+195195+ pub(crate) fn output(&mut self, c: Register) {
196196+ let value = self.load_register(c);
197197+ if let Some(stdout) = self.stdout.as_mut() {
198198+ let buffer = [(value & 0xff) as u8];
199199+ stdout.write_all(&buffer).unwrap();
200200+ }
201201+ }
202202+203203+ pub(crate) fn input(&mut self, c: Register) {
204204+ if let Some(stdin) = self.stdin.as_mut() {
205205+ let mut buffer = vec![0];
206206+ match stdin.read_exact(&mut buffer) {
207207+ Ok(()) => self.save_register(c, buffer[0] as u32),
208208+ Err(_) => self.save_register(c, u32::MAX),
209209+ }
210210+ } else {
211211+ self.save_register(c, u32::MAX);
212212+ }
213213+ }
214214+215215+ pub(crate) fn load_program(&mut self, b: Register, c: Register) {
216216+ let block = self.load_register(b);
217217+218218+ // Source array is always copied to array[0], but there
219219+ // is no point copying array[0] to array[0].
220220+ if block != 0 {
221221+ let duplicated = self.duplicate_memory(block);
222222+ let ops = crate::ops::decode(duplicated);
223223+ self.ops = ops;
224224+ }
225225+226226+ self.program_counter = self.load_register(c);
227227+ }
228228+229229+ pub(crate) fn orthography(&mut self, a: Register, value: u32) {
230230+ self.save_register(a, value);
231231+ }
232232+233233+ #[cold]
234234+ #[inline(never)]
235235+ pub(crate) fn illegal_instruction(&self) -> ! {
236236+ panic!(
237237+ "illegal instruction: {:08x}, pc: {:08x}, r: {:08x?}",
238238+ self.memory[0][self.program_counter.into_index()],
239239+ self.program_counter,
240240+ self.registers
241241+ )
242242+ }
243243+244244+ pub(crate) fn load_memory(&self, block: u32, offset: u32) -> u32 {
245245+ let block = block.into_index();
246246+ let offset = offset.into_index();
247247+ assert!(block < self.memory.len() && offset < self.memory[block].len());
248248+ self.memory[block][offset]
249249+ }
250250+251251+ pub(crate) fn store_memory(&mut self, block: u32, offset: u32, value: u32) {
252252+ let block = block.into_index();
253253+ let offset = offset.into_index();
254254+ assert!(block < self.memory.len() && offset < self.memory[block].len());
255255+ self.memory[block][offset] = value
256256+ }
257257+258258+ /// Duplicates a block of memory.
259259+ ///
260260+ /// The block is copied to the first block of memory.
261261+ pub(crate) fn duplicate_memory(&mut self, block: u32) -> &[u32] {
262262+ let block = block.into_index();
263263+ assert!(block < self.memory.len());
264264+ self.memory[0] = self.memory[block].clone();
265265+ &self.memory[0]
266266+ }
267267+268268+ /// Allocates a block of memory of the specified length.
269269+ pub(crate) fn allocate_memory(&mut self, length: u32) -> u32 {
270270+ if let Some(index) = self.free_blocks.pop() {
271271+ self.memory[index.into_index()] = Self::new_block(length.into_index());
272272+ index
273273+ } else {
274274+ self.memory.push(Self::new_block(length.into_index()));
275275+ (self.memory.len() - 1) as u32
276276+ }
277277+ }
278278+279279+ /// Frees a block of memory.
280280+ pub(crate) fn free_memory(&mut self, block: u32) {
281281+ assert!(block.into_index() < self.memory.len());
282282+ self.free_blocks.push(block);
283283+ self.memory[block.into_index()] = Self::new_block(0);
284284+ }
285285+286286+ /// Creates a new block of memory.
287287+ ///
288288+ /// The block is initialised with `len` zeroes.
289289+ pub(crate) fn new_block(len: usize) -> SmallVec<[u32; SMALLVEC_SIZE]> {
290290+ smallvec::smallvec![0; len]
291291+ }
292292+}
293293+294294+#[cfg(test)]
295295+pub(crate) mod tests {
296296+ use super::*;
297297+298298+ #[test]
299299+ #[should_panic]
300300+ fn empty_program() {
301301+ Um::new(vec![]).run();
302302+ }
303303+304304+ #[test]
305305+ fn just_halt() {
306306+ Um::new(vec![0x70000000]).run();
307307+ }
308308+309309+ #[test]
310310+ #[cfg(feature = "asm")]
311311+ fn hello_world() {
312312+ let program = asm::assemble(include_str!("../files/hello-world.asm"));
313313+ let mut buffer = Vec::new();
314314+ Um::new(program).stdout(&mut buffer).run();
315315+ assert_eq!(&buffer, b"Hello, world!\n");
316316+ }
317317+318318+ #[test]
319319+ #[cfg(feature = "asm")]
320320+ fn cat() {
321321+ let program = asm::assemble(include_str!("../files/cat.asm"));
322322+ let input = include_bytes!("lib.rs");
323323+324324+ let mut reader = std::io::Cursor::new(input);
325325+ let mut buffer = Vec::new();
326326+327327+ Um::new(program)
328328+ .stdin(&mut reader)
329329+ .stdout(&mut buffer)
330330+ .run();
331331+332332+ assert_eq!(&buffer, &input);
333333+ }
334334+}