Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ out/**
!out/.gitkeep
build/**
!build/.gitkeep
.DS_Store
49 changes: 49 additions & 0 deletions src/ext/b/zbs.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// -----------------------------------------------------------------------------
// Zbs Extension – Single-Bit Instructions (RV32)
// Reference:
// RISC-V Bitmanip Extension Specification v1.0.0
// Section 5.4 – Zbs (Single-Bit Instructions)
//
// Notes:
// - Purely combinational logic
// - Bit index = reg2[4:0]
// - R/I distinction handled in decode stage
// -----------------------------------------------------------------------------

module zbs (
input data_t reg1 // rs1 operand
, input data_t reg2 // rs2 or immediate (bit index source)
, input logic [1:0] inst // operation selector
, output data_t out //result
);

logic [4:0] index;
data_t mask;

always_comb
index = reg2[4:0];

always_comb
mask = data_t'(32'h1) << index;

always_comb
case (inst)

// 00 : bclr / bclri → clear selected bit
2'b00: out = reg1 & ~mask;

// 01 : bset / bseti → set selected bit
2'b01: out = reg1 | mask;

// 10 : binv / binvi → invert selected bit
2'b10: out = reg1 ^ mask;

// 11 : bext / bexti → extract selected bit (to bit[0])
2'b11: out = (reg1 >> index) & data_t'(32'h1);

// others → safe default
default: out = '0;

endcase

endmodule
133 changes: 133 additions & 0 deletions test/zbs_tb.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
`timescale 1ns/1ns
`include "test/utils.svh"

module zbs_tb;

logic [31:0] reg1;
logic [31:0] reg2;
logic [2:0] inst;
logic [31:0] out;

logic [31:0] expected;

zbs uut
( .reg1 ( reg1 )
, .reg2 ( reg2 )
, .inst ( inst )
, .out ( out )
);

initial begin

// -------- bclr test --------
reg1 = 32'b1010;
reg2 = 32'd1; // clear bit 1
inst = 3'b000;
#10;

expected = reg1 & ~(32'h1 << reg2[4:0]);

assert (out == expected)
else $fatal("bclr failed: expected %b got %b", expected, out);


// -------- bset test --------
reg1 = 32'b1110;
reg2 = 32'd0; // set bit 0
inst = 3'b001;
#10;

expected = reg1 | (32'h1 << reg2[4:0]);

assert (out == expected)
else $fatal("bset failed: expected %b got %b", expected, out);


// -------- binv test --------
reg1 = 32'b1010;
reg2 = 32'd1;
inst = 3'b010;
#10;

expected = reg1 ^ (32'h1 << reg2[4:0]);

assert (out == expected)
else $fatal("binv failed: expected %b got %b", expected, out);


// -------- bext test --------
reg1 = 32'b1010;
reg2 = 32'd3;
inst = 3'b011;
#10;

expected = {31'b0, reg1[reg2[4:0]]};

assert (out == expected)
else $fatal("bext failed: expected %b got %b", expected, out);

// -------- Edge Cases ---------

// Bit 0 boundary
reg1 = 32'hFFFFFFFF;
reg2 = 32'd0;
inst = 3'b000; // bclr
#10;

expected = reg1 & ~(32'h1 << reg2[4:0]);

assert (out == expected)
else $fatal("corner case bit0 failed");


// Bit 31 boundary
reg1 = 32'hFFFFFFFF;
reg2 = 32'd31;
inst = 3'b000; // bclr
#10;

expected = reg1 & ~(32'h1 << reg2[4:0]);

assert (out == expected)
else $fatal("corner case bit31 failed");


// ----------- Randomized Testing (Experimental) -----------

repeat (1000) begin

reg1 = $urandom;
reg2 = $urandom % 32;
inst = $urandom % 4;

#1;

case (inst)

3'b000: expected = reg1 & ~(32'h1 << reg2[4:0]);

3'b001: expected = reg1 | (32'h1 << reg2[4:0]);

3'b010: expected = reg1 ^ (32'h1 << reg2[4:0]);

3'b011: expected = {31'b0, reg1[reg2[4:0]]};

default: expected = 32'd0;

endcase

assert (out == expected) else
$fatal("random test failed: inst=%0d reg1=%h reg2=%d expected=%h got=%h"
, inst, reg1, reg2, expected, out);

end

$display("All tests passed!");

$finish;

end

`SETUP_VCD_DUMP(zbs_tb)

endmodule
Loading