Skip to content

Commit

Permalink
isa: decode ALU instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Oct 22, 2024
1 parent 0584dca commit 824c824
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 56 deletions.
204 changes: 187 additions & 17 deletions src/isa/alu/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,21 @@
use core::ops::RangeInclusive;

use super::{CtrlInstr, MaybeU128, RegInstr};
use crate::core::{SiteId, A};
use crate::core::{RegA, SiteId, A};
use crate::isa::bytecode::CodeEofError;
#[cfg(feature = "GFA")]
use crate::isa::FieldInstr;
use crate::isa::{Bytecode, BytecodeRead, BytecodeWrite, Instr, InstructionSet, ReservedInstr};
use crate::Site;

impl<Id: SiteId, Ext: InstructionSet<Id> + Bytecode<Id>> Bytecode<Id> for Instr<Id, Ext> {
fn op_range() -> RangeInclusive<u8> { todo!() }
fn op_range() -> RangeInclusive<u8> { 0..=0xFF }

fn opcode_byte(&self) -> u8 {
match self {
Instr::Ctrl(instr) => instr.opcode_byte(),
Instr::Reg(instr) => Bytecode::<Id>::opcode_byte(instr),
#[cfg(feature = "GFA")]
Instr::GFqA(instr) => Bytecode::<Id>::opcode_byte(instr),
Instr::Reserved(instr) => Bytecode::<Id>::opcode_byte(instr),
Instr::Ext(instr) => instr.opcode_byte(),
Expand All @@ -48,6 +51,7 @@ impl<Id: SiteId, Ext: InstructionSet<Id> + Bytecode<Id>> Bytecode<Id> for Instr<
match self {
Instr::Ctrl(instr) => instr.encode_operands(writer),
Instr::Reg(instr) => instr.encode_operands(writer),
#[cfg(feature = "GFA")]
Instr::GFqA(instr) => instr.encode_operands(writer),
Instr::Reserved(instr) => instr.encode_operands(writer),
Instr::Ext(instr) => instr.encode_operands(writer),
Expand All @@ -59,33 +63,87 @@ impl<Id: SiteId, Ext: InstructionSet<Id> + Bytecode<Id>> Bytecode<Id> for Instr<
Self: Sized,
R: BytecodeRead<Id>,
{
todo!()
match opcode {
op if CtrlInstr::<Id>::op_range().contains(&op) => {
CtrlInstr::<Id>::decode_operands(reader, op).map(Self::Ctrl)
}
op if <RegInstr as Bytecode<Id>>::op_range().contains(&op) => {
<RegInstr as Bytecode<Id>>::decode_operands(reader, op).map(Self::Reg)
}
#[cfg(feature = "GFA")]
op if <FieldInstr as Bytecode<Id>>::op_range().contains(&op) => {
<FieldInstr as Bytecode<Id>>::decode_operands(reader, op).map(Self::GFqA)
}
0x80..=0xFF => Ext::decode_operands(reader, opcode).map(Self::Ext),
_ => ReservedInstr::decode_operands(reader, opcode).map(Self::Reserved),
}
}
}

impl<Id: SiteId> Bytecode<Id> for ReservedInstr {
fn op_range() -> RangeInclusive<u8> { todo!() }
fn op_range() -> RangeInclusive<u8> { 0..=0x7F }

fn opcode_byte(&self) -> u8 { todo!() }
fn opcode_byte(&self) -> u8 { self.0 }

fn encode_operands<W>(&self, writer: &mut W) -> Result<(), W::Error>
fn encode_operands<W>(&self, _writer: &mut W) -> Result<(), W::Error>
where W: BytecodeWrite<Id> {
todo!()
Ok(())
}

fn decode_operands<R>(reader: &mut R, opcode: u8) -> Result<Self, CodeEofError>
fn decode_operands<R>(_reader: &mut R, opcode: u8) -> Result<Self, CodeEofError>
where
Self: Sized,
R: BytecodeRead<Id>,
{
todo!()
Ok(ReservedInstr(opcode))
}
}

impl<Id: SiteId> CtrlInstr<Id> {
const START: u8 = 0;
const END: u8 = Self::START + Self::STOP;

const NOP: u8 = 0;
const NOCO: u8 = 1;
const CHK: u8 = 2;
const FAIL: u8 = 3;
const RSET: u8 = 4;
const JMP: u8 = 5;
const JIFNE: u8 = 6;
const JIFAIL: u8 = 7;
const SH: u8 = 8;
const SHNE: u8 = 9;
const SHFAIL: u8 = 10;
const EXEC: u8 = 11;
const FN: u8 = 12;
const CALL: u8 = 13;
const RET: u8 = 14;
const STOP: u8 = 15;
}

impl<Id: SiteId> Bytecode<Id> for CtrlInstr<Id> {
fn op_range() -> RangeInclusive<u8> { todo!() }
fn op_range() -> RangeInclusive<u8> { Self::START..=Self::END }

fn opcode_byte(&self) -> u8 { todo!() }
fn opcode_byte(&self) -> u8 {
match self {
CtrlInstr::Nop => Self::NOP,
CtrlInstr::Chk => Self::CHK,
CtrlInstr::NotCo => Self::NOCO,
CtrlInstr::FailCk => Self::FAIL,
CtrlInstr::RsetCk => Self::RSET,
CtrlInstr::Jmp { .. } => Self::JMP,
CtrlInstr::JifCo { .. } => Self::JIFNE,
CtrlInstr::JifCk { .. } => Self::JIFAIL,
CtrlInstr::Sh { .. } => Self::SH,
CtrlInstr::ShNe { .. } => Self::SHNE,
CtrlInstr::ShFail { .. } => Self::SHFAIL,
CtrlInstr::Exec { .. } => Self::EXEC,
CtrlInstr::Fn { .. } => Self::FN,
CtrlInstr::Call { .. } => Self::CALL,
CtrlInstr::Ret => Self::RET,
CtrlInstr::Stop => Self::STOP,
}
}

fn encode_operands<W>(&self, writer: &mut W) -> Result<(), W::Error>
where W: BytecodeWrite<Id> {
Expand All @@ -101,8 +159,8 @@ impl<Id: SiteId> Bytecode<Id> for CtrlInstr<Id> {
CtrlInstr::Jmp { pos } | CtrlInstr::JifCo { pos } | CtrlInstr::JifCk { pos } | CtrlInstr::Fn { pos } => {
writer.write_fixed(pos.to_le_bytes())?
}
CtrlInstr::Shift { shift } | CtrlInstr::ShIfCo { shift } | CtrlInstr::ShIfCk { shift } => {
writer.write_byte(shift.to_le_bytes()[0])?
CtrlInstr::Sh { shift } | CtrlInstr::ShNe { shift } | CtrlInstr::ShFail { shift } => {
writer.write_fixed(shift.to_le_bytes())?
}
CtrlInstr::Call { site } | CtrlInstr::Exec { site } => {
let site = Site::new(site.prog_id, site.offset);
Expand All @@ -118,14 +176,83 @@ impl<Id: SiteId> Bytecode<Id> for CtrlInstr<Id> {
Self: Sized,
R: BytecodeRead<Id>,
{
todo!()
Ok(match opcode {
Self::NOP => Self::Nop,
Self::CHK => Self::Chk,
Self::FAIL => Self::FailCk,
Self::RSET => Self::RsetCk,
Self::NOCO => Self::NotCo,
Self::RET => Self::Ret,
Self::STOP => Self::Stop,

Self::JMP => CtrlInstr::Jmp {
pos: reader.read_fixed(u16::from_le_bytes)?,
},
Self::JIFNE => CtrlInstr::JifCo {
pos: reader.read_fixed(u16::from_le_bytes)?,
},
Self::JIFAIL => CtrlInstr::JifCk {
pos: reader.read_fixed(u16::from_le_bytes)?,
},
Self::FN => CtrlInstr::Fn {
pos: reader.read_fixed(u16::from_le_bytes)?,
},

Self::SH => CtrlInstr::Sh {
shift: reader.read_fixed(i8::from_le_bytes)?,
},
Self::SHNE => CtrlInstr::ShNe {
shift: reader.read_fixed(i8::from_le_bytes)?,
},
Self::SHFAIL => CtrlInstr::ShFail {
shift: reader.read_fixed(i8::from_le_bytes)?,
},

Self::CALL => {
let prog_id = reader.read_ref()?;
let offset = reader.read_word()?;
let site = Site::new(prog_id, offset);
CtrlInstr::Call { site }
}
Self::EXEC => {
let prog_id = reader.read_ref()?;
let offset = reader.read_word()?;
let site = Site::new(prog_id, offset);
CtrlInstr::Exec { site }
}

_ => unreachable!(),
})
}
}

impl RegInstr {
const START: u8 = 16;
const END: u8 = Self::START + Self::EQ;

const CLR: u8 = 16;
const PUT: u8 = 17;
const PIF: u8 = 18;
const TEST: u8 = 19;
const CPY: u8 = 20;
const SWP: u8 = 21;
const EQ: u8 = 22;
}

impl<Id: SiteId> Bytecode<Id> for RegInstr {
fn op_range() -> RangeInclusive<u8> { todo!() }
fn op_range() -> RangeInclusive<u8> { Self::START..=Self::END }

fn opcode_byte(&self) -> u8 { todo!() }
fn opcode_byte(&self) -> u8 {
match self {
RegInstr::Clr { .. } => Self::CLR,
RegInstr::Put { .. } => Self::PUT,
RegInstr::Pif { .. } => Self::PIF,
RegInstr::Test { .. } => Self::TEST,
RegInstr::Cpy { .. } => Self::CPY,
RegInstr::Swp { .. } => Self::SWP,
RegInstr::Eq { .. } => Self::EQ,
}
}

fn encode_operands<W>(&self, writer: &mut W) -> Result<(), W::Error>
where W: BytecodeWrite<Id> {
Expand Down Expand Up @@ -170,6 +297,49 @@ impl<Id: SiteId> Bytecode<Id> for RegInstr {
Self: Sized,
R: BytecodeRead<Id>,
{
todo!()
Ok(match opcode {
RegInstr::CLR => {
let dst = RegA::from(reader.read_byte()?);
RegInstr::Clr { dst }
}
RegInstr::PUT | RegInstr::PIF => {
let dst = RegA::from(reader.read_byte()?);
let val = match dst.a() {
A::A8 => reader.read_byte().map(|v| v as u128),
A::A16 => reader.read_word().map(|v| v as u128),
A::A32 => reader.read_fixed(u32::from_le_bytes).map(|v| v as u128),
A::A64 => reader.read_fixed(u64::from_le_bytes).map(|v| v as u128),
A::A128 => reader.read_fixed(u128::from_le_bytes),
}
.ok()
.into();

if opcode == RegInstr::PUT {
RegInstr::Put { dst, val }
} else {
RegInstr::Pif { dst, val }
}
}
RegInstr::TEST => {
let src = RegA::from(reader.read_byte()?);
RegInstr::Test { src }
}
RegInstr::CPY => {
let dst = RegA::from(reader.read_byte()?);
let src = RegA::from(reader.read_byte()?);
RegInstr::Cpy { dst, src }
}
RegInstr::SWP => {
let src_dst1 = RegA::from(reader.read_byte()?);
let src_dst2 = RegA::from(reader.read_byte()?);
RegInstr::Swp { src_dst1, src_dst2 }
}
RegInstr::EQ => {
let src1 = RegA::from(reader.read_byte()?);
let src2 = RegA::from(reader.read_byte()?);
RegInstr::Eq { src1, src2 }
}
_ => unreachable!(),
})
}
}
6 changes: 3 additions & 3 deletions src/isa/alu/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,15 @@ impl<Id: SiteId> Instruction<Id> for CtrlInstr<Id> {
return ExecStep::Jump(pos);
}
}
CtrlInstr::Shift { shift } => {
CtrlInstr::Sh { shift } => {
return shift_jump(shift);
}
CtrlInstr::ShIfCo { shift } => {
CtrlInstr::ShNe { shift } => {
if core.co() {
return shift_jump(shift);
}
}
CtrlInstr::ShIfCk { shift } => {
CtrlInstr::ShFail { shift } => {
if core.ck() == Status::Fail {
return shift_jump(shift);
}
Expand Down
23 changes: 16 additions & 7 deletions src/isa/alu/instr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ pub enum MaybeU128 {
NoData,
}

impl From<Option<u128>> for MaybeU128 {
fn from(value: Option<u128>) -> Self {
match value {
None => MaybeU128::NoData,
Some(val) => MaybeU128::U128(val),
}
}
}

/// Control flow instructions.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Display)]
#[display(inner)]
Expand All @@ -47,6 +56,10 @@ pub enum CtrlInstr<Id: SiteId> {
#[display("chk")]
Chk,

/// Invert `co` register.
#[display("not co")]
NotCo,

/// Set `ck` register to a failed state.
#[display("put ck, :fail")]
FailCk,
Expand All @@ -55,10 +68,6 @@ pub enum CtrlInstr<Id: SiteId> {
#[display("put ck, :ok")]
RsetCk,

/// Invert `co` register.
#[display("not co")]
NotCo,

/// Jump to location (unconditionally).
#[display("jmp {pos:04X}:h")]
Jmp { pos: u16 },
Expand All @@ -73,15 +82,15 @@ pub enum CtrlInstr<Id: SiteId> {

/// Relative jump.
#[display("jmp {shift:+03X}:h")]
Shift { shift: i8 },
Sh { shift: i8 },

/// Relative jump if `co` is true.
#[display("jif co, {shift:+03X}:h")]
ShIfCo { shift: i8 },
ShNe { shift: i8 },

/// Relative jump if `ck` is in a failed state.
#[display("jif ck, {shift:+03X}:h")]
ShIfCk { shift: i8 },
ShFail { shift: i8 },

/// External jump.
#[display("jmp {site}")]
Expand Down
10 changes: 7 additions & 3 deletions src/isa/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use core::fmt::{Debug, Display};

use amplify::confinement::TinyOrdSet;
use strict_encoding::stl::AlphaCapsNum;
use strict_encoding::RString;
use strict_encoding::{RString, StrictDumb};

#[cfg(feature = "GFA")]
use super::FieldInstr;
Expand All @@ -51,11 +51,15 @@ macro_rules! isa {

#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)]
#[wrapper(Deref, Display, FromStr)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_ALUVM, dumb = { Self::from("DUMB") })]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_ALUVM)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
pub struct IsaId(RString<AlphaCapsNum, AlphaCapsNum, 1, ISA_ID_MAX_LEN>);

impl StrictDumb for IsaId {
fn strict_dumb() -> Self { Self::from("DUMB") }
}

impl From<&'static str> for IsaId {
fn from(id: &'static str) -> Self { Self(RString::from(id)) }
}
Expand Down
Loading

0 comments on commit 824c824

Please sign in to comment.