FP instruction implementations
This commit is contained in:
parent
29a7dfa277
commit
ac07031631
4 changed files with 295 additions and 22 deletions
|
@ -1,5 +1,17 @@
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use crate::{env::Env, instructions::kind::Kind};
|
use crate::{env::Env, instructions::kind::Kind};
|
||||||
|
|
||||||
|
/// Always "safe" because f32 and i32 have the same size.
|
||||||
|
fn u32_to_f32(i: u32) -> f32 {
|
||||||
|
unsafe { mem::transmute(i) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Always "safe" because f32 and i32 have the same size.
|
||||||
|
fn _f32_to_u32(f: f32) -> u32 {
|
||||||
|
unsafe { mem::transmute(f) }
|
||||||
|
}
|
||||||
|
|
||||||
/// lui rd, imm
|
/// lui rd, imm
|
||||||
fn lui(env: &mut Env, rd: usize, imm: u32) {
|
fn lui(env: &mut Env, rd: usize, imm: u32) {
|
||||||
env.set_register(rd, imm);
|
env.set_register(rd, imm);
|
||||||
|
@ -25,6 +37,30 @@ fn mul(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
env.set_register(rd, env.get_register(ra).wrapping_mul(env.get_register(rb)));
|
env.set_register(rd, env.get_register(ra).wrapping_mul(env.get_register(rb)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// mulh rd, ra, rb (SxS)
|
||||||
|
fn mulh(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(
|
||||||
|
rd,
|
||||||
|
(env.get_register(ra) as i64 * env.get_register(rb) as i64 >> 32) as u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// mulhsu rd, ra, rb (SxU)
|
||||||
|
fn mulhsu(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(
|
||||||
|
rd,
|
||||||
|
(env.get_register(ra) as i64 * env.get_register(rb) as i64 >> 32) as u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// mulhu rd, ra, rb (UxU)
|
||||||
|
fn mulu(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(
|
||||||
|
rd,
|
||||||
|
(env.get_register(ra) as u64 * env.get_register(rb) as u64 >> 32) as u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// beq ra, rb, imm
|
/// beq ra, rb, imm
|
||||||
fn beq(env: &mut Env, ra: usize, rb: usize, imm: u32) -> bool {
|
fn beq(env: &mut Env, ra: usize, rb: usize, imm: u32) -> bool {
|
||||||
if env.get_register(ra) == env.get_register(rb) {
|
if env.get_register(ra) == env.get_register(rb) {
|
||||||
|
@ -40,6 +76,16 @@ fn jal(env: &mut Env, rd: usize, imm: u32) {
|
||||||
env.pc = env.pc.wrapping_add(imm);
|
env.pc = env.pc.wrapping_add(imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// fadd.s fd, fa, fb
|
||||||
|
fn fadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize) {
|
||||||
|
env.set_fregister(fd, env.get_fregister(fa) + env.get_fregister(fb));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// fdiv.s fd, fa, fb
|
||||||
|
fn fdiv_s(env: &mut Env, fd: usize, fa: usize, fb: usize) {
|
||||||
|
env.set_fregister(fd, env.get_fregister(fa) / env.get_fregister(fb));
|
||||||
|
}
|
||||||
|
|
||||||
/// fmadd.s fd, fa, fb, fc
|
/// fmadd.s fd, fa, fb, fc
|
||||||
fn fmadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize, fc: usize) {
|
fn fmadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize, fc: usize) {
|
||||||
env.set_fregister(
|
env.set_fregister(
|
||||||
|
@ -48,6 +94,19 @@ fn fmadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize, fc: usize) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// fcvt.s.w fd, ra
|
||||||
|
fn fcvt_s_w(env: &mut Env, fd: usize, ra: usize) {
|
||||||
|
env.set_fregister(fd, env.get_register(ra) as i32 as f32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// fmv.w.x fd, ra
|
||||||
|
fn fmv_w_x(env: &mut Env, fd: usize, ra: usize) {
|
||||||
|
env.set_fregister(fd, u32_to_f32(env.get_register(ra)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes the instruction.
|
||||||
|
///
|
||||||
|
/// Returns true if the instruction is a jump.
|
||||||
pub fn run_instruction(env: &mut Env, instruction: u32) -> bool {
|
pub fn run_instruction(env: &mut Env, instruction: u32) -> bool {
|
||||||
let (kind, _) = Kind::to_op(instruction);
|
let (kind, _) = Kind::to_op(instruction);
|
||||||
let mut regs = kind.get_regs().unwrap();
|
let mut regs = kind.get_regs().unwrap();
|
||||||
|
@ -81,15 +140,43 @@ pub fn run_instruction(env: &mut Env, instruction: u32) -> bool {
|
||||||
mul(env, rd, ra, rb);
|
mul(env, rd, ra, rb);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
0b0110011 if funct3 == 0b001 && funct7 == 0b0000001 => {
|
||||||
|
mulh(env, rd, ra, rb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b0110011 if funct3 == 0b010 && funct7 == 0b0000001 => {
|
||||||
|
mulhsu(env, rd, ra, rb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b0110011 if funct3 == 0b011 && funct7 == 0b0000001 => {
|
||||||
|
mulu(env, rd, ra, rb);
|
||||||
|
false
|
||||||
|
}
|
||||||
0b1100011 => beq(env, ra, rb, imm.unwrap()),
|
0b1100011 => beq(env, ra, rb, imm.unwrap()),
|
||||||
0b1101111 => {
|
0b1101111 => {
|
||||||
jal(env, rd, imm.unwrap());
|
jal(env, rd, imm.unwrap());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
0b1000011 => {
|
0b1010011 if funct7 == 0x00 => {
|
||||||
|
fadd_s(env, fd, fa, fb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x0c => {
|
||||||
|
fdiv_s(env, fd, fa, fb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b1000011 if fb == 0 => {
|
||||||
fmadd_s(env, fd, fa, fb, fc);
|
fmadd_s(env, fd, fa, fb, fc);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
0b1010011 if funct7 == 0x68 => {
|
||||||
|
fcvt_s_w(env, fd, ra);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x78 => {
|
||||||
|
fmv_w_x(env, fd, ra);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => todo!("op: {:032b}", instruction),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
158
src/info.rs
158
src/info.rs
|
@ -2,29 +2,161 @@ use colored::Colorize;
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
|
|
||||||
pub fn info(_env: &Env, op: &str, args: Vec<String>) -> Vec<String> {
|
/// Display a helpful message about an instruction.
|
||||||
match op {
|
///
|
||||||
"nop" => vec!["Do nothing - wait 1 cycle".to_string()],
|
/// Returns the message and, if needed, tags to highlight specific registers ([x regs...], [fregs...]).
|
||||||
"li" => vec![format!("load {} into the register {}", args[1], args[0])],
|
pub fn info(
|
||||||
|
env: &Env,
|
||||||
|
op: &str,
|
||||||
|
args: Vec<String>,
|
||||||
|
display_mode: char,
|
||||||
|
) -> (String, (Vec<usize>, Vec<usize>)) {
|
||||||
|
let args: Vec<_> = args
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| {
|
||||||
|
if let Ok(num) = a.parse::<u32>() {
|
||||||
|
match display_mode {
|
||||||
|
'd' => num.to_string(),
|
||||||
|
's' => (num as i32).to_string(),
|
||||||
|
'b' => format!("{:032b}", num),
|
||||||
|
'h' => format!("{:08x}", num),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut tag = (vec![], vec![]);
|
||||||
|
let msg = match op {
|
||||||
|
"nop" => vec!["do nothing".to_string()],
|
||||||
|
"li" => vec![format!(
|
||||||
|
"load {} into {}",
|
||||||
|
args[1].italic().yellow(),
|
||||||
|
args[0].red()
|
||||||
|
)],
|
||||||
"lui" => {
|
"lui" => {
|
||||||
let imm = format!("{:032b}", args[1].parse::<i32>().unwrap() as u32)
|
let imm = format!("{:032b}", args[1].parse::<i32>().unwrap() as u32)
|
||||||
.chars()
|
.chars()
|
||||||
.rev()
|
.rev()
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
vec![
|
vec![
|
||||||
format!(
|
format!("load the upper 20 bits of {} into {}", args[1], args[0]),
|
||||||
"load the upper 20 bits of {} into {}",
|
|
||||||
args[1], args[0]
|
|
||||||
),
|
|
||||||
format!(
|
format!(
|
||||||
"{} = {}{}",
|
"{} = {}{}",
|
||||||
args[1],
|
args[1].italic().yellow(),
|
||||||
imm[12..32].to_string().red(),
|
imm[12..32].to_string().green(),
|
||||||
imm[0..12].to_string()
|
imm[0..12].to_string().strikethrough().black()
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"{:>1$} ← {2} << 12",
|
||||||
|
args[0].blue(),
|
||||||
|
args[1].to_string().len(),
|
||||||
|
imm[12..32].to_string(),
|
||||||
),
|
),
|
||||||
format!("{:>1$} <- {2}{3:0>12}", args[0], args[1].to_string().len() - 1, imm[12..32].to_string(), "0".to_string().bold()),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
"add" => {
|
||||||
|
tag = (
|
||||||
|
vec![
|
||||||
|
env.str_to_register(&args[1]).unwrap(),
|
||||||
|
env.str_to_register(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"add the values of {0} and {1} and store the result in {2}\n{2} ← {0} + {1}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"addi" => {
|
||||||
|
tag = (
|
||||||
|
vec![
|
||||||
|
env.str_to_register(&args[1]).unwrap(),
|
||||||
|
env.str_to_register(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"add the values of {0} and {1} and store the result in {2}\n{2} ← {0} + {1}",
|
||||||
|
args[2].blue(),
|
||||||
|
args[1].italic().yellow(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"sub" => vec![format!(
|
||||||
|
"subtract the value of {} from the value of {} and store the result in {}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)],
|
||||||
|
"mul" => {
|
||||||
|
tag = (
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
env.str_to_fregister(&args[1]).unwrap(),
|
||||||
|
env.str_to_fregister(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"multiply the values of {0} and {1} and store the result in {2}\n{2} ← {0} ✕ {1}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"fadd.s" => {
|
||||||
|
tag = (
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
env.str_to_fregister(&args[1]).unwrap(),
|
||||||
|
env.str_to_fregister(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"add the values of {0} and {1} and store the result in {2}\n{2} ← {0} + {1}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"fdiv.s" => {
|
||||||
|
tag = (
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
env.str_to_fregister(&args[1]).unwrap(),
|
||||||
|
env.str_to_fregister(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"divide the value of {0} by the value of {1} and store the result in {2}\n{2} ← {0} ÷ {1}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"fcvt.s.w" => {
|
||||||
|
tag = (vec![env.str_to_register(&args[1]).unwrap()], vec![]);
|
||||||
|
vec![format!(
|
||||||
|
"convert the value of {} to a float and store it in {}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"fmv.w.x" => {
|
||||||
|
tag = (vec![env.str_to_register(&args[1]).unwrap()], vec![]);
|
||||||
|
vec![format!(
|
||||||
|
"interpret the value of {0} as a float and store it in {1}\n{1} ← {0}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
op => todo!("{}", op),
|
||||||
}
|
}
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
(msg, tag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub mod kind {
|
||||||
|
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
|
|
||||||
|
/// A pseudo instruction is an instruction that
|
||||||
/// will be converted by the engine to real instructions
|
/// will be converted by the engine to real instructions
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pseudo(pub &'static str);
|
pub struct Pseudo(pub &'static str);
|
||||||
|
@ -218,8 +219,20 @@ pub mod kind {
|
||||||
}
|
}
|
||||||
0b1100011 => (Kind::B(B(instruction)), "beq".into()),
|
0b1100011 => (Kind::B(B(instruction)), "beq".into()),
|
||||||
0b1101111 => (Kind::J(J(instruction)), "jal".into()),
|
0b1101111 => (Kind::J(J(instruction)), "jal".into()),
|
||||||
|
0b1010011 if funct7 == 0x00 => {
|
||||||
|
(Kind::R(R(instruction)), "fadd.s".into())
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x0c => {
|
||||||
|
(Kind::R(R(instruction)), "fdiv.s".into())
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x68 => {
|
||||||
|
(Kind::R(R(instruction)), "fcvt.s.w".into())
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x78 => {
|
||||||
|
(Kind::R(R(instruction)), "fmv.w.x".into())
|
||||||
|
}
|
||||||
other => {
|
other => {
|
||||||
println!("{:07b}", other);
|
println!("todo: opcode={:07b}", other);
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,6 +522,52 @@ pub fn instruction(op: &str) -> Option<(Kind, Vec<Arg>)> {
|
||||||
}),
|
}),
|
||||||
vec![Arg::Register(0), Arg::Symbol],
|
vec![Arg::Register(0), Arg::Symbol],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// F Extension - assune rm is 0b000
|
||||||
|
|
||||||
|
// Arithmetic
|
||||||
|
"fadd.s" => (
|
||||||
|
Kind::R({
|
||||||
|
let mut r = R(0);
|
||||||
|
r.set_funct7(0x00);
|
||||||
|
r.set_funct3(0b000);
|
||||||
|
r.set_opcode(0b1010011);
|
||||||
|
r
|
||||||
|
}),
|
||||||
|
vec![Arg::Register(0), Arg::Register(1), Arg::Register(2)],
|
||||||
|
),
|
||||||
|
"fdiv.s" => (
|
||||||
|
Kind::R({
|
||||||
|
let mut r = R(0);
|
||||||
|
r.set_funct7(0x0c);
|
||||||
|
r.set_funct3(0b000);
|
||||||
|
r.set_opcode(0b1010011);
|
||||||
|
r
|
||||||
|
}),
|
||||||
|
vec![Arg::Register(0), Arg::Register(1), Arg::Register(2)],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Move / Convert
|
||||||
|
"fcvt.s.w" => (
|
||||||
|
Kind::R({
|
||||||
|
let mut r = R(0);
|
||||||
|
r.set_funct7(0x68);
|
||||||
|
r.set_funct3(0b000);
|
||||||
|
r.set_opcode(0b1010011);
|
||||||
|
r
|
||||||
|
}),
|
||||||
|
vec![Arg::Register(0), Arg::Register(1)], // rb is not used
|
||||||
|
),
|
||||||
|
"fmv.w.x" => (
|
||||||
|
Kind::R({
|
||||||
|
let mut r = R(0);
|
||||||
|
r.set_funct7(0x78);
|
||||||
|
r.set_funct3(0b000);
|
||||||
|
r.set_opcode(0b1010011);
|
||||||
|
r
|
||||||
|
}),
|
||||||
|
vec![Arg::Register(0), Arg::Register(1)], // rb is not used
|
||||||
|
),
|
||||||
op => unimplemented!("{}", op),
|
op => unimplemented!("{}", op),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -612,7 +671,7 @@ pub fn handle_pseudo(
|
||||||
// lui rd, imm
|
// lui rd, imm
|
||||||
with(
|
with(
|
||||||
get_instruction("lui"),
|
get_instruction("lui"),
|
||||||
(imm & 0xFFFF000) | ((imm >> 11) & 0x1) << 12,
|
(imm & 0xfffff000) ^ ((imm >> 11) & 0x1) << 12,
|
||||||
regs.clone(),
|
regs.clone(),
|
||||||
),
|
),
|
||||||
// addi rd, rd, imm
|
// addi rd, rd, imm
|
||||||
|
|
|
@ -67,8 +67,6 @@ fn lui() {
|
||||||
// U-Type
|
// U-Type
|
||||||
// | imm20 | rd | opcode
|
// | imm20 | rd | opcode
|
||||||
// 00000011010100101001 01010 0110111
|
// 00000011010100101001 01010 0110111
|
||||||
// 11111111111101111011 01010 0110111
|
|
||||||
// 00001111111101111011 01010 0110111
|
|
||||||
};
|
};
|
||||||
// lui a0 13609
|
// lui a0 13609
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -146,7 +144,6 @@ fn addi() {
|
||||||
// I-Type
|
// I-Type
|
||||||
// | imm12 | ra |f3 | rd | opcode
|
// | imm12 | ra |f3 | rd | opcode
|
||||||
// 000000000001 01010 000 01010 0010011
|
// 000000000001 01010 000 01010 0010011
|
||||||
// 000000000001 01010 000 01010 0010011 (Ripes)
|
|
||||||
};
|
};
|
||||||
// addi a0 a0 1
|
// addi a0 a0 1
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -173,8 +170,6 @@ fn beq() {
|
||||||
// B-Type
|
// B-Type
|
||||||
// | imm7 | rb | ra |f3 |imm5 | opcode
|
// | imm7 | rb | ra |f3 |imm5 | opcode
|
||||||
// 0000000 01011 01010 000 00100 1100011
|
// 0000000 01011 01010 000 00100 1100011
|
||||||
// 0000000 01011 01010 000 00100 1100011 (Ripes)
|
|
||||||
// 0000000 01011 01010 000 01000 1100011
|
|
||||||
};
|
};
|
||||||
// beq a0 a1 4
|
// beq a0 a1 4
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Reference in a new issue