Skip to content

Commit

Permalink
isa: encode ALU instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Oct 21, 2024
1 parent b170f5f commit 0584dca
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 123 deletions.
83 changes: 76 additions & 7 deletions src/isa/alu/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,34 @@

use core::ops::RangeInclusive;

use super::{CtrlInstr, RegInstr};
use crate::core::SiteId;
use super::{CtrlInstr, MaybeU128, RegInstr};
use crate::core::{SiteId, A};
use crate::isa::bytecode::CodeEofError;
use crate::isa::{Bytecode, BytecodeRead, BytecodeWrite, Instr, InstructionSet, ReservedInstr};
use crate::Site;

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

fn opcode_byte(&self) -> u8 { todo!() }
fn opcode_byte(&self) -> u8 {
match self {
Instr::Ctrl(instr) => instr.opcode_byte(),
Instr::Reg(instr) => Bytecode::<Id>::opcode_byte(instr),
Instr::GFqA(instr) => Bytecode::<Id>::opcode_byte(instr),
Instr::Reserved(instr) => Bytecode::<Id>::opcode_byte(instr),
Instr::Ext(instr) => instr.opcode_byte(),
}
}

fn encode_operands<W>(&self, writer: &mut W) -> Result<(), W::Error>
where W: BytecodeWrite<Id> {
todo!()
match self {
Instr::Ctrl(instr) => instr.encode_operands(writer),
Instr::Reg(instr) => instr.encode_operands(writer),
Instr::GFqA(instr) => instr.encode_operands(writer),
Instr::Reserved(instr) => instr.encode_operands(writer),
Instr::Ext(instr) => instr.encode_operands(writer),
}
}

fn decode_operands<R>(reader: &mut R, opcode: u8) -> Result<Self, CodeEofError>
Expand Down Expand Up @@ -74,7 +89,28 @@ impl<Id: SiteId> Bytecode<Id> for CtrlInstr<Id> {

fn encode_operands<W>(&self, writer: &mut W) -> Result<(), W::Error>
where W: BytecodeWrite<Id> {
todo!()
match *self {
CtrlInstr::Nop
| CtrlInstr::Chk
| CtrlInstr::FailCk
| CtrlInstr::RsetCk
| CtrlInstr::NotCo
| CtrlInstr::Ret
| CtrlInstr::Stop => {}

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::Call { site } | CtrlInstr::Exec { site } => {
let site = Site::new(site.prog_id, site.offset);
writer.write_ref(site.prog_id)?;
writer.write_word(site.offset)?;
}
}
Ok(())
}

fn decode_operands<R>(reader: &mut R, opcode: u8) -> Result<Self, CodeEofError>
Expand All @@ -93,7 +129,40 @@ impl<Id: SiteId> Bytecode<Id> for RegInstr {

fn encode_operands<W>(&self, writer: &mut W) -> Result<(), W::Error>
where W: BytecodeWrite<Id> {
todo!()
match *self {
RegInstr::Clr { dst } => {
writer.write_byte(dst.to_u8())?;
}
RegInstr::Put { dst, val } | RegInstr::Pif { dst, val } => {
writer.write_byte(dst.to_u8())?;
let MaybeU128::U128(val) = val else {
panic!("an attempt to serialize program with missed data");
};
match dst.a() {
A::A8 => writer.write_byte(val as u8)?,
A::A16 => writer.write_word(val as u16)?,
A::A32 => writer.write_fixed(val.to_le_bytes())?,
A::A64 => writer.write_fixed(val.to_le_bytes())?,
A::A128 => writer.write_fixed(val.to_le_bytes())?,
}
}
RegInstr::Test { src } => {
writer.write_byte(src.to_u8())?;
}
RegInstr::Cpy { dst, src } => {
writer.write_byte(dst.to_u8())?;
writer.write_byte(src.to_u8())?;
}
RegInstr::Swp { src_dst1, src_dst2 } => {
writer.write_byte(src_dst1.to_u8())?;
writer.write_byte(src_dst2.to_u8())?;
}
RegInstr::Eq { src1, src2 } => {
writer.write_byte(src1.to_u8())?;
writer.write_byte(src2.to_u8())?;
}
}
Ok(())
}

fn decode_operands<R>(reader: &mut R, opcode: u8) -> Result<Self, CodeEofError>
Expand Down
4 changes: 2 additions & 2 deletions src/isa/alu/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ impl<Id: SiteId> Instruction<Id> for ReservedInstr {
impl<Id: SiteId> Instruction<Id> for CtrlInstr<Id> {
type Context<'ctx> = ();

fn src_regs(&self) -> BTreeSet<Reg> { todo!() }
fn src_regs(&self) -> BTreeSet<Reg> { none!() }

fn dst_regs(&self) -> BTreeSet<Reg> { todo!() }
fn dst_regs(&self) -> BTreeSet<Reg> { none!() }

fn op_data_bytes(&self) -> u16 { todo!() }

Expand Down
68 changes: 34 additions & 34 deletions src/isa/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub trait Bytecode<Id: SiteId> {
/// Write an instruction as bytecode.
fn encode_instr<W>(&self, writer: &mut W) -> Result<(), W::Error>
where W: BytecodeWrite<Id> {
writer.write_u8(self.opcode_byte())?;
writer.write_byte(self.opcode_byte())?;
self.encode_operands(writer)?;
writer.check_aligned();
Ok(())
Expand All @@ -66,7 +66,7 @@ pub trait Bytecode<Id: SiteId> {
Self: Sized,
R: BytecodeRead<Id>,
{
let opcode = reader.read_u8()?;
let opcode = reader.read_byte()?;
let instr = Self::decode_operands(reader, opcode)?;
reader.check_aligned();
Ok(instr)
Expand All @@ -85,7 +85,7 @@ pub trait Bytecode<Id: SiteId> {
pub struct CodeEofError;

/// Reader from a bytecode for instruction deserialization.
pub trait BytecodeRead<Id> {
pub trait BytecodeRead<Id: SiteId> {
/// Return current byte offset of the cursor. Does not account for bits.
/// If the position is exactly at EOF, returns `None`.
fn pos(&self) -> u16;
Expand All @@ -102,38 +102,38 @@ pub trait BytecodeRead<Id> {
fn peek_byte(&self) -> Result<u8, CodeEofError>;

fn read_reg_a(&mut self) -> Result<RegA, CodeEofError> {
let a = A::from(self.read_u3()?);
let idx = IdxA::from(self.read_u5()?);
let a = A::from(self.read_3bits()?);
let idx = IdxA::from(self.read_5bits()?);
Ok(RegA::with(a, idx))
}
fn read_pair_a(&mut self) -> Result<(A, IdxA, IdxA), CodeEofError> {
let a = A::from(self.read_u3()?);
let idx1 = IdxA::from(self.read_u5()?);
let idx2 = IdxA::from(self.read_u5()?);
let a = A::from(self.read_3bits()?);
let idx1 = IdxA::from(self.read_5bits()?);
let idx2 = IdxA::from(self.read_5bits()?);
Ok((a, idx1, idx2))
}

/// Read single bit as a bool value.
fn read_bool(&mut self) -> Result<bool, CodeEofError> { Ok(self.read_u1()? == u1::ONE) }
fn read_bool(&mut self) -> Result<bool, CodeEofError> { Ok(self.read_1bit()? == u1::ONE) }
/// Read single bit.
fn read_u1(&mut self) -> Result<u1, CodeEofError>;
fn read_1bit(&mut self) -> Result<u1, CodeEofError>;
/// Read two bits.
fn read_u2(&mut self) -> Result<u2, CodeEofError>;
fn read_2bits(&mut self) -> Result<u2, CodeEofError>;
/// Read three bits.
fn read_u3(&mut self) -> Result<u3, CodeEofError>;
fn read_3bits(&mut self) -> Result<u3, CodeEofError>;
/// Read four bits.
fn read_u4(&mut self) -> Result<u4, CodeEofError>;
fn read_4bits(&mut self) -> Result<u4, CodeEofError>;
/// Read five bits.
fn read_u5(&mut self) -> Result<u5, CodeEofError>;
fn read_5bits(&mut self) -> Result<u5, CodeEofError>;
/// Read six bits.
fn read_u6(&mut self) -> Result<u6, CodeEofError>;
fn read_6bits(&mut self) -> Result<u6, CodeEofError>;
/// Read seven bits.
fn read_u7(&mut self) -> Result<u7, CodeEofError>;
fn read_7bits(&mut self) -> Result<u7, CodeEofError>;

/// Read unsigned 8-bit integer.
fn read_u8(&mut self) -> Result<u8, CodeEofError>;
/// Read unsigned 16-bit integer.
fn read_u16(&mut self) -> Result<u16, CodeEofError>;
/// Read byte.
fn read_byte(&mut self) -> Result<u8, CodeEofError>;
/// Read word.
fn read_word(&mut self) -> Result<u16, CodeEofError>;

/// Read fixed number of bytes and convert it into a result type.
///
Expand Down Expand Up @@ -164,36 +164,36 @@ pub trait BytecodeRead<Id> {
}

/// Writer converting instructions into a bytecode.
pub trait BytecodeWrite<Id> {
pub trait BytecodeWrite<Id: SiteId> {
type Error: Error;

/// Write a single bit from a bool value.
fn write_bool(&mut self, data: bool) -> Result<(), Self::Error> {
self.write_u1(if data { u1::ONE } else { u1::ZERO })
self.write_1bit(if data { u1::ONE } else { u1::ZERO })
}

/// Write a single bit.
fn write_u1(&mut self, data: impl Into<u1>) -> Result<(), Self::Error>;
fn write_1bit(&mut self, data: impl Into<u1>) -> Result<(), Self::Error>;
/// Write two bits.
fn write_u2(&mut self, data: impl Into<u2>) -> Result<(), Self::Error>;
fn write_2bits(&mut self, data: impl Into<u2>) -> Result<(), Self::Error>;
/// Write three bits.
fn write_u3(&mut self, data: impl Into<u3>) -> Result<(), Self::Error>;
fn write_3bits(&mut self, data: impl Into<u3>) -> Result<(), Self::Error>;
/// Write four bits.
fn write_u4(&mut self, data: impl Into<u4>) -> Result<(), Self::Error>;
fn write_4bits(&mut self, data: impl Into<u4>) -> Result<(), Self::Error>;
/// Write five bits.
fn write_u5(&mut self, data: impl Into<u5>) -> Result<(), Self::Error>;
fn write_5bits(&mut self, data: impl Into<u5>) -> Result<(), Self::Error>;
/// Write six bits.
fn write_u6(&mut self, data: impl Into<u6>) -> Result<(), Self::Error>;
fn write_6bits(&mut self, data: impl Into<u6>) -> Result<(), Self::Error>;
/// Write seven bits.
fn write_u7(&mut self, data: impl Into<u7>) -> Result<(), Self::Error>;
fn write_7bits(&mut self, data: impl Into<u7>) -> Result<(), Self::Error>;

/// Write unsigned 8-bit integer.
fn write_u8(&mut self, data: u8) -> Result<(), Self::Error>;
/// Write unsigned 16-bit integer.
fn write_u16(&mut self, data: u16) -> Result<(), Self::Error>;
/// Write byte.
fn write_byte(&mut self, data: u8) -> Result<(), Self::Error>;
/// Write word.
fn write_word(&mut self, data: u16) -> Result<(), Self::Error>;

/// Write data representable as a fixed-length byte array.
fn write_fixed<N, const LEN: usize>(&mut self, data: [u8; LEN]) -> Result<(), Self::Error>;
fn write_fixed<const LEN: usize>(&mut self, data: [u8; LEN]) -> Result<(), Self::Error>;

/// Write variable-length byte string.
fn write_bytes(&mut self, data: &[u8]) -> Result<(), Self::Error>;
Expand Down
50 changes: 25 additions & 25 deletions src/isa/gfa/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,29 +56,29 @@ impl<Id: SiteId> Bytecode<Id> for FieldInstr {
where W: BytecodeWrite<Id> {
match *self {
FieldInstr::IncMod { src_dst, val } => {
writer.write_u8(src_dst.to_u8())?;
writer.write_u8(val)?;
writer.write_byte(src_dst.to_u8())?;
writer.write_byte(val)?;
}
FieldInstr::DecMod { src_dst, val } => {
writer.write_u8(src_dst.to_u8())?;
writer.write_u8(val)?;
writer.write_byte(src_dst.to_u8())?;
writer.write_byte(val)?;
}
FieldInstr::NegMod { src_dst } => {
writer.write_u8(src_dst.to_u8())?;
writer.write_byte(src_dst.to_u8())?;
}
FieldInstr::AddMod { reg, dst, src1, src2 } => {
writer.write_u1(u1::ZERO)?;
writer.write_u3(reg.to_u3())?;
writer.write_u4(dst.to_u4())?;
writer.write_u4(src1.to_u4())?;
writer.write_u4(src2.to_u4())?;
writer.write_1bit(u1::ZERO)?;
writer.write_3bits(reg.to_u3())?;
writer.write_4bits(dst.to_u4())?;
writer.write_4bits(src1.to_u4())?;
writer.write_4bits(src2.to_u4())?;
}
FieldInstr::MulMod { reg, dst, src1, src2 } => {
writer.write_u1(u1::ONE)?;
writer.write_u3(reg.to_u3())?;
writer.write_u4(dst.to_u4())?;
writer.write_u4(src1.to_u4())?;
writer.write_u4(src2.to_u4())?;
writer.write_1bit(u1::ONE)?;
writer.write_3bits(reg.to_u3())?;
writer.write_4bits(dst.to_u4())?;
writer.write_4bits(src1.to_u4())?;
writer.write_4bits(src2.to_u4())?;
}
}
Ok(())
Expand All @@ -91,25 +91,25 @@ impl<Id: SiteId> Bytecode<Id> for FieldInstr {
{
Ok(match opcode - Self::START {
Self::INC_MOD => {
let src_dst = RegA::from(reader.read_u8()?);
let val = reader.read_u8()?;
let src_dst = RegA::from(reader.read_byte()?);
let val = reader.read_byte()?;
FieldInstr::IncMod { src_dst, val }
}
Self::DEC_MOD => {
let src_dst = RegA::from(reader.read_u8()?);
let val = reader.read_u8()?;
let src_dst = RegA::from(reader.read_byte()?);
let val = reader.read_byte()?;
FieldInstr::IncMod { src_dst, val }
}
Self::NEG_MOD => {
let src_dst = RegA::from(reader.read_u8()?);
let src_dst = RegA::from(reader.read_byte()?);
FieldInstr::NegMod { src_dst }
}
Self::ADD_MUL => {
let subop = reader.read_u1()?;
let reg = A::from(reader.read_u3()?);
let dst = IdxAl::from(reader.read_u4()?);
let src1 = IdxAl::from(reader.read_u4()?);
let src2 = IdxAl::from(reader.read_u4()?);
let subop = reader.read_1bit()?;
let reg = A::from(reader.read_3bits()?);
let dst = IdxAl::from(reader.read_4bits()?);
let src1 = IdxAl::from(reader.read_4bits()?);
let src2 = IdxAl::from(reader.read_4bits()?);
match subop {
u1::ZERO => FieldInstr::AddMod { reg, dst, src1, src2 },
u1::ONE => FieldInstr::MulMod { reg, dst, src1, src2 },
Expand Down
Loading

0 comments on commit 0584dca

Please sign in to comment.