virmin/
insn.rs

1use std::cmp;
2use num::BigUint;
3use crate::domain::Countable;
4use crate::domain::{Bits,Bytes};
5use crate::machine::Width;
6use crate::machine::MicroCode;
7
8// ================================================================
9// Format
10// ================================================================
11
12/// Defines a format for a class of related instructions.  For
13/// example, some instructions might not take any operands.  Others
14/// might take, say, three register operands, etc.  The following
15/// illustrates:
16///
17/// ```text
18///    +-+-+-+-+-+-+-+-+
19///    |7   5|    2|1 0|
20///    +-+-+-+-+-+-+-+-+
21///    | #2  | #1  |Op |
22///    +-+-+-+-+-+-+-+-+
23/// ```
24/// Here, we see one possible layout for an instruction class which
25/// includes two three-bit operands, and a two bit opcode.  This means
26/// we can have at most four instructions in this class, and each
27/// operand can take on eight distinct values.
28#[derive(PartialEq)]
29pub struct Format {
30    /// Determines the overall width (in bytes) of an instruction in
31    /// this class.  Generally speaking, virtual machines normally
32    /// have all instructions of the same width (e.g. 32bits) and, in
33    /// such case, `width` will be the same for all formats.  However,
34    /// it is possible that a virtual machine has different sized
35    /// instructions (e.g. 16bit instructions, and 32bit "double"
36    /// instructions).
37    width: Bytes,
38    /// Human-readable label for this format
39    label: String,
40    /// Determine the number of distinct instructions in this class.
41    opcode : Bits,
42    /// Determine the number and size of operands for all instructions
43    /// in this class.
44    operands: Vec<Bits>
45}
46
47impl Format {
48    pub fn new(width:Bytes, label: &str, opcode: Bits, operands: &[Bits]) -> Format {	
49	let r = Format{width,label:label.to_string(),opcode,operands:operands.to_vec()};
50	// Sanity check there is enough space
51	assert!(width.count() >= r.count());
52	//
53	r
54    }
55}
56
57impl Countable for Format {
58    fn count(&self) -> BigUint {
59	let mut count = BigUint::from(self.opcode.count());
60	//
61	for op in &self.operands {
62	    count = count * op.count();
63	}
64	//
65	count
66    }
67}
68
69// =====================================================
70// Abstract Microcode
71// =====================================================
72
73/// Represents an abstract microcode instruction.  This is
74/// (effectively) a template for constructing a concrete microcode
75/// instruction from a concrete instantiation of an instruction
76/// (i.e. where all operands have known values).
77pub enum AbstractMicroCode {
78    /// X := Y (w bits)    
79    Copy(Operand,Operand,Width),
80    /// pc := I
81    Goto(Operand),    
82    /// pc := pc + I
83    Jump(Operand),
84    /// X := i
85    Load(Operand,u64,Width)	
86}
87
88impl AbstractMicroCode {
89    /// Determine how many operands this microcode requires.  This is
90    /// necessary to sanity check that, for a given instruction
91    /// format, this microcode instruction makes sense.
92    pub fn arity(&self) -> usize {
93	match &self {
94	    AbstractMicroCode::Copy(x,y,w) => {
95		cmp::max(x.arity(),y.arity())
96	    }
97	    AbstractMicroCode::Load(x,i,w) => {
98		x.arity()
99	    }
100	    _ => {
101		todo!("implement more instructions")
102	    }
103	}
104    }
105    /// Given a set of concrete operands, reduce this abstract
106    /// microcode instruction into a concrete microcode instruction.    
107    pub fn to_microcode(&self, operands: &[usize]) -> MicroCode {
108	match &self {
109	    AbstractMicroCode::Copy(x,y,w) => {
110		let l = x.as_usize(operands);
111		let r = y.as_usize(operands);
112		MicroCode::Copy(l,r,*w)
113	    }
114	    AbstractMicroCode::Load(x,i,w) => {
115		let l = x.as_usize(operands);
116		MicroCode::Load(l,*i,*w)
117	    }
118	    _ => {
119		todo!("implement more instructions")
120	    }
121	}
122    }
123}
124
125/// Represents an arbitrary expression over one or more instruction
126/// operands.  For each instruction instantiation, an operand
127/// expression can be evaluated to a constant.
128pub enum Operand {
129    /// A constant value which can be used in various ways.  For
130    /// example, it can be used to identify a fixed location in the
131    /// underlying machine; or, it could be used as part of a more
132    /// complex operand expression.
133    Const(usize),
134    /// An operand value read from the instantiated instruction.
135    Var(usize)
136}
137
138impl Operand {
139    /// Determine the arity of an operand expression.  That is, how
140    /// many operands are needed for it to evaluate.
141    pub fn arity(&self) -> usize {
142	match &self {
143	    Operand::Const(i) => {
144		0
145	    }
146	    Operand::Var(v) => {
147		v + 1
148	    }
149	}
150    }
151
152    pub fn as_usize(&self, operands: &[usize]) -> usize {
153	match &self {
154	    Operand::Const(i) => {
155		*i
156	    }
157	    Operand::Var(v) => {
158		operands[*v]
159	    }
160	}
161    }
162}
163
164// =====================================================
165// Instruction
166// =====================================================
167
168pub struct Instruction<'a> {
169    /// Mnemonic for referring to the instruction.  Every instruction
170    /// should have a unique mnemonic.
171    mnemonic: &'a str,
172    /// Format associated with this instruction.
173    format: &'a Format,
174    /// Machine semantics associated with instruction.
175    semantic: &'a [AbstractMicroCode]
176}
177
178impl<'a> Instruction<'a> {
179    pub fn new(mnemonic: &'a str, format: &'a Format, semantic: &'a [AbstractMicroCode]) -> Self {
180	for code in semantic {
181	    assert!(code.arity() <= format.operands.len());
182	}
183	Instruction{mnemonic,format,semantic}
184    }
185
186    pub fn to_microcode(&self, operands: &[usize]) -> Vec<MicroCode> {
187	let mut microcode = Vec::new();
188	for c in self.semantic {
189	    microcode.push(c.to_microcode(operands));
190	}
191	microcode
192    }
193}
194
195// =====================================================
196// Instruction Set
197// =====================================================   
198
199/// A collection of instructions.
200pub struct InstructionSet<'a> {
201    insns : &'a [Instruction<'a>]
202}
203
204impl<'a> InstructionSet<'a> {
205    pub fn new(insns : &'a [Instruction<'a>]) -> Self {
206	InstructionSet{insns}
207    }
208}
209