From 9dfa1bc102245f17a7d643eb5f12298743b251e6 Mon Sep 17 00:00:00 2001 From: Morgan Thomas Date: Wed, 24 Apr 2024 12:30:42 -0400 Subject: [PATCH] issue/159: signed inequality comparison instructions --- alu_u32/src/lt/mod.rs | 123 +++++++++++++++++++++++++++++++++++++++++- basic/src/lib.rs | 11 +++- machine/src/core.rs | 7 +++ opcodes/src/lib.rs | 4 ++ 4 files changed, 142 insertions(+), 3 deletions(-) diff --git a/alu_u32/src/lt/mod.rs b/alu_u32/src/lt/mod.rs index 3aee13b6..e93cadff 100644 --- a/alu_u32/src/lt/mod.rs +++ b/alu_u32/src/lt/mod.rs @@ -10,7 +10,7 @@ use valida_cpu::MachineWithCpuChip; use valida_machine::{ instructions, Chip, Instruction, Interaction, Operands, Word, MEMORY_CELL_BYTES, }; -use valida_opcodes::{LT32, LTE32}; +use valida_opcodes::{LT32, LTE32, SLE32, SLT32}; use p3_air::VirtualPairCol; use p3_field::{AbstractField, Field, PrimeField}; @@ -26,6 +26,8 @@ pub mod stark; pub enum Operation { Lt32(Word, Word, Word), // (dst, src1, src2) Lte32(Word, Word, Word), // (dst, src1, src2) + Slt32(Word, Word, Word), // (dst, src1, src2) + Sle32(Word, Word, Word), // (dst, src1, src2) } #[derive(Default)] @@ -98,6 +100,16 @@ impl Lt32Chip { cols.is_lte = F::one(); self.set_cols(cols, a, b, c); } + Operation::Slt32(a, b, c) => { + // TODO: this is just a placeholder + cols.is_lt = F::one(); + self.set_cols(cols, a, b, c); + } + Operation::Sle32(a, b, c) => { + // TODO: this is just a placeholder + cols.is_lte = F::one(); + self.set_cols(cols, a, b, c); + } } row } @@ -134,7 +146,12 @@ pub trait MachineWithLt32Chip: MachineWithCpuChip { fn lt_u32_mut(&mut self) -> &mut Lt32Chip; } -instructions!(Lt32Instruction, Lte32Instruction); +instructions!( + Lt32Instruction, + Lte32Instruction, + Slt32Instruction, + Sle32Instruction +); impl Instruction for Lt32Instruction where @@ -233,3 +250,105 @@ where state.cpu_mut().push_bus_op(imm, opcode, ops); } } + +impl Instruction for Slt32Instruction +where + M: MachineWithLt32Chip, + F: Field, +{ + const OPCODE: u32 = SLT32; + + fn execute(state: &mut M, ops: Operands) { + let opcode = >::OPCODE; + let clk = state.cpu().clock; + let pc = state.cpu().pc; + let mut imm: Option> = None; + let read_addr_1 = (state.cpu().fp as i32 + ops.b()) as u32; + let write_addr = (state.cpu().fp as i32 + ops.a()) as u32; + let src1: Word = if ops.d() == 1 { + let b = (ops.b() as u32).into(); + imm = Some(b); + b + } else { + state + .mem_mut() + .read(clk, read_addr_1, true, pc, opcode, 0, "") + }; + let src2: Word = if ops.is_imm() == 1 { + let c = (ops.c() as u32).into(); + imm = Some(c); + c + } else { + let read_addr_2 = (state.cpu().fp as i32 + ops.c()) as u32; + state + .mem_mut() + .read(clk, read_addr_2, true, pc, opcode, 1, "") + }; + + let src1_i: i32 = src1.into(); + let src2_i: i32 = src2.into(); + let dst = if src1_i < src2_i { + Word::from(1) + } else { + Word::from(0) + }; + state.mem_mut().write(clk, write_addr, dst, true); + + state + .lt_u32_mut() + .operations + .push(Operation::Slt32(dst, src1, src2)); + state.cpu_mut().push_bus_op(imm, opcode, ops); + } +} + +impl Instruction for Sle32Instruction +where + M: MachineWithLt32Chip, + F: Field, +{ + const OPCODE: u32 = SLE32; + + fn execute(state: &mut M, ops: Operands) { + let opcode = >::OPCODE; + let clk = state.cpu().clock; + let pc = state.cpu().pc; + let mut imm: Option> = None; + let read_addr_1 = (state.cpu().fp as i32 + ops.b()) as u32; + let write_addr = (state.cpu().fp as i32 + ops.a()) as u32; + let src1: Word = if ops.d() == 1 { + let b = (ops.b() as u32).into(); + imm = Some(b); + b + } else { + state + .mem_mut() + .read(clk, read_addr_1, true, pc, opcode, 0, "") + }; + let src2: Word = if ops.is_imm() == 1 { + let c = (ops.c() as u32).into(); + imm = Some(c); + c + } else { + let read_addr_2 = (state.cpu().fp as i32 + ops.c()) as u32; + state + .mem_mut() + .read(clk, read_addr_2, true, pc, opcode, 1, "") + }; + + let src1_i: i32 = src1.into(); + let src2_i: i32 = src2.into(); + let dst = if src1_i <= src2_i { + Word::from(1) + } else { + Word::from(0) + }; + state.mem_mut().write(clk, write_addr, dst, true); + + state + .lt_u32_mut() + .operations + .push(Operation::Sle32(dst, src1, src2)); + state.cpu_mut().push_bus_op(imm, opcode, ops); + } +} diff --git a/basic/src/lib.rs b/basic/src/lib.rs index d1df172c..29aef541 100644 --- a/basic/src/lib.rs +++ b/basic/src/lib.rs @@ -23,7 +23,10 @@ use valida_alu_u32::{ }, com::{Com32Chip, Eq32Instruction, MachineWithCom32Chip, Ne32Instruction}, div::{Div32Chip, Div32Instruction, MachineWithDiv32Chip, SDiv32Instruction}, - lt::{Lt32Chip, Lt32Instruction, Lte32Instruction, MachineWithLt32Chip}, + lt::{ + Lt32Chip, Lt32Instruction, Lte32Instruction, MachineWithLt32Chip, Sle32Instruction, + Slt32Instruction, + }, mul::{ MachineWithMul32Chip, Mul32Chip, Mul32Instruction, Mulhs32Instruction, Mulhu32Instruction, }, @@ -1144,6 +1147,12 @@ impl Machine for BasicMachine { >::OPCODE => { Lte32Instruction::execute_with_advice::(self, ops, advice) } + >::OPCODE => { + Slt32Instruction::execute_with_advice::(self, ops, advice) + } + >::OPCODE => { + Sle32Instruction::execute_with_advice::(self, ops, advice) + } >::OPCODE => { And32Instruction::execute_with_advice::(self, ops, advice) } diff --git a/machine/src/core.rs b/machine/src/core.rs index 51120003..f8544620 100644 --- a/machine/src/core.rs +++ b/machine/src/core.rs @@ -1,5 +1,6 @@ use super::MEMORY_CELL_BYTES; use core::cmp::Ordering; +use core::mem::transmute; use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Index, IndexMut, Mul, Shl, Shr, Sub}; use p3_field::{Field, PrimeField}; @@ -82,6 +83,12 @@ impl Into for Word { } } +impl Into for Word { + fn into(self) -> i32 { + unsafe { transmute::(self.into()) } + } +} + impl From for Word { fn from(value: u32) -> Self { let mut result = Word::::default(); diff --git a/opcodes/src/lib.rs b/opcodes/src/lib.rs index 5ffd9104..fee6411f 100644 --- a/opcodes/src/lib.rs +++ b/opcodes/src/lib.rs @@ -36,6 +36,8 @@ pub enum Opcode { MULHS32 = 114, LTE32 = 115, EQ32 = 116, + SLT32 = 117, + SLE32 = 118, ADD = 200, SUB = 201, MUL = 202, @@ -85,6 +87,8 @@ declare_opcode!(SRA32); declare_opcode!(MULHS32); declare_opcode!(LTE32); declare_opcode!(EQ32); +declare_opcode!(SLT32); +declare_opcode!(SLE32); /// NATIVE FIELD declare_opcode!(ADD);