Update skeleton

This commit is contained in:
Jeehoon Kang
2020-05-29 21:27:35 +09:00
parent 599fb7ca35
commit 4c850d5801
13 changed files with 398 additions and 521 deletions

View File

@@ -87,7 +87,7 @@ pub enum SymbolType {
#[derive(Debug, Clone, PartialEq)]
pub enum Instruction {
/// R-type instruction format
/// https://content.riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf (11p, 104p)
/// https://riscv.org/specifications/isa-spec-pdf/ (16p, 129p)
RType {
instr: RType,
rd: Register,
@@ -95,7 +95,7 @@ pub enum Instruction {
rs2: Register,
},
/// I-type instruction format
/// https://content.riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf (11p, 104p)
/// https://riscv.org/specifications/isa-spec-pdf/ (16p, 129p)
IType {
instr: IType,
rd: Register,
@@ -103,26 +103,109 @@ pub enum Instruction {
imm: isize,
},
/// S-type instruction format
/// https://content.riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf (11p, 104p)
/// https://riscv.org/specifications/isa-spec-pdf/ (16p, 129p)
SType {
instr: SType,
rs1: Register,
rs2: Register,
imm: isize,
},
/// B-type instruction format
/// https://riscv.org/specifications/isa-spec-pdf/ (16p, 129p)
BType {
instr: BType,
rs1: Register,
rs2: Register,
imm: Label,
},
Pseudo(Pseudo),
}
/// If the enum variant contains `Option<DataSize>`,
/// it means that the instructions used may vary according to `DataSize`.
/// Use 'Some' if RISC-V ISA provides instruction to support a specific 'DataSize',
/// if not, 'None' which means to use default instruction.
/// Because KECC uses RV64 (RISC-V ISA for 64-bit architecture),
/// KECC uses `Some` if `DataSize` is `Word`, if not, use `None`.
/// https://riscv.org/specifications/isa-spec-pdf/ (35p)
///
/// If the enum variant contains `bool`,
/// It means that different instructions exist
/// depending on whether the operand is signed or not.
#[derive(Debug, Clone, PartialEq)]
pub enum RType {
Add(Option<DataSize>),
Sub(Option<DataSize>),
Mul(Option<DataSize>),
Div(Option<DataSize>, bool),
Slt(bool),
Xor,
}
impl RType {
pub fn add(dtype: ir::Dtype) -> Self {
let data_size =
DataSize::try_from(dtype).expect("`data_size` must be derived from `dtype`");
let data_size = if data_size == DataSize::Word {
Some(data_size)
} else {
None
};
Self::Add(data_size)
}
pub fn sub(dtype: ir::Dtype) -> Self {
let data_size =
DataSize::try_from(dtype).expect("`data_size` must be derived from `dtype`");
let data_size = if data_size == DataSize::Word {
Some(data_size)
} else {
None
};
Self::Sub(data_size)
}
pub fn mul(dtype: ir::Dtype) -> Self {
let data_size =
DataSize::try_from(dtype).expect("`data_size` must be derived from `dtype`");
let data_size = if data_size == DataSize::Word {
Some(data_size)
} else {
None
};
Self::Mul(data_size)
}
pub fn div(dtype: ir::Dtype, is_signed: bool) -> Self {
let data_size =
DataSize::try_from(dtype).expect("`data_size` must be derived from `dtype`");
let data_size = if data_size == DataSize::Word {
Some(data_size)
} else {
None
};
Self::Div(data_size, is_signed)
}
}
/// If the enum variant contains `Option<DataSize>`,
/// it means that the instructions used may vary according to `DataSize`.
/// Use 'Some' if RISC-V ISA provides instruction to support a specific 'DataSize',
/// if not, 'None' which means to use default instruction.
/// Because KECC uses RV64 (RISC-V ISA for 64-bit architecture),
/// KECC uses `Some` if `DataSize` is `Word`, if not, use `None`.
/// https://riscv.org/specifications/isa-spec-pdf/ (35p)
#[derive(Debug, Clone, PartialEq)]
pub enum IType {
Load(DataSize),
Addi(Option<DataSize>),
Andi,
Slli,
Srli,
}
impl IType {
@@ -131,9 +214,9 @@ impl IType {
pub const ADDI: Self = Self::Addi(None);
pub fn load(dtype: ir::Dtype) -> Self {
let data_align =
DataSize::try_from(dtype).expect("`data_align` must be derived from `dtype`");
Self::Load(data_align)
let data_size =
DataSize::try_from(dtype).expect("`data_size` must be derived from `dtype`");
Self::Load(data_size)
}
}
@@ -147,12 +230,20 @@ impl SType {
pub const SD: Self = Self::Store(DataSize::Double);
pub fn store(dtype: ir::Dtype) -> Self {
let data_align =
DataSize::try_from(dtype).expect("`data_align` must be derived from `dtype`");
Self::Store(data_align)
let data_size =
DataSize::try_from(dtype).expect("`data_size` must be derived from `dtype`");
Self::Store(data_size)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BType {
Beq,
Bne,
Blt(bool),
Bge(bool),
}
/// The assembler implements a number of convenience psuedo-instructions that are formed from
/// instructions in the base ISA, but have implicit arguments or in some case reversed arguments,
/// that result in distinct semantics.
@@ -163,9 +254,17 @@ pub enum Pseudo {
/// li rd, immediate
Li { rd: Register, imm: isize },
/// mv rd, rs
Mv { rs: Register, rd: Register },
Mv { rd: Register, rs: Register },
/// neg(w) rd, rs
Neg {
data_size: Option<DataSize>,
rs: Register,
rd: Register,
},
/// sext.w rd, rs
SextW { rs: Register, rd: Register },
SextW { rd: Register, rs: Register },
/// seqz rd, rs
Seqz { rd: Register, rs: Register },
/// j offset
J { offset: Label },
/// jr rs
@@ -176,6 +275,20 @@ pub enum Pseudo {
Call { offset: Label },
}
impl Pseudo {
pub fn neg(dtype: ir::Dtype, rs: Register, rd: Register) -> Self {
let data_size =
DataSize::try_from(dtype).expect("`data_size` must be derived from `dtype`");
let data_size = if data_size == DataSize::Word {
Some(data_size)
} else {
None
};
Self::Neg { data_size, rs, rd }
}
}
/// `Label` is used as branch, unconditional jump targets and symbol offsets.
/// https://github.com/rv8-io/rv8-io.github.io/blob/master/asm.md#labels
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -220,7 +333,7 @@ impl TryFrom<ir::Dtype> for DataSize {
// TODO: Add calling convention information (caller/callee-save registers)
/// ABI name for RISC-V integer and floating-point register
/// https://content.riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf (109p)
/// https://content.riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf (155p)
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
pub enum Register {
Zero,
@@ -237,10 +350,35 @@ pub enum Register {
}
impl Register {
// TODO: add all possible registers in the future
pub const T0: Self = Self::Temp(0);
pub const T1: Self = Self::Temp(1);
pub const T2: Self = Self::Temp(2);
pub const T3: Self = Self::Temp(3);
pub const T4: Self = Self::Temp(4);
pub const T5: Self = Self::Temp(5);
pub const T6: Self = Self::Temp(6);
pub const S0: Self = Self::Saved(0);
pub const S1: Self = Self::Saved(1);
pub const S2: Self = Self::Saved(2);
pub const S3: Self = Self::Saved(3);
pub const S4: Self = Self::Saved(4);
pub const S5: Self = Self::Saved(5);
pub const S6: Self = Self::Saved(6);
pub const S7: Self = Self::Saved(7);
pub const S8: Self = Self::Saved(8);
pub const S9: Self = Self::Saved(9);
pub const S10: Self = Self::Saved(10);
pub const S11: Self = Self::Saved(11);
pub const A0: Self = Self::Arg(0);
pub const A1: Self = Self::Arg(1);
pub const A2: Self = Self::Arg(2);
pub const A3: Self = Self::Arg(3);
pub const A4: Self = Self::Arg(4);
pub const A5: Self = Self::Arg(5);
pub const A6: Self = Self::Arg(6);
pub const A7: Self = Self::Arg(7);
pub fn temp(id: usize) -> Self {
assert!(id <= 6);