Files
Toooba/src_Core/BSV_Additional_Libs/ByteLane.bsv

219 lines
8.0 KiB
Plaintext

// Copyright (c) 2017-2019 Bluespec, Inc. All Rights Reserved
package ByteLane;
// ================================================================
// Library for 'adjusting/unadjusting' bytes on a wider bus
// Example: a 64b bit bus can be regarded as 8 "byte lanes"
// with each lane selected by the lower 3 bits of an address.
// Such a bus typically carries data of 1, 2, 4 or 8 bytes.
// For 1,2, and 4, different apps use one of two representations:
// - carry the data on contiguous lower-order bytes, with a separate
// indication of how many bytes are being carried (1,2,4)
// - carry the data bytes on the lanes corresponding to the byte addresses,
// along with a 'mask' indicating which bytes are valid:
// Lane: 7 6 5 4 3 2 1 0
// x x x x D D D D 4-byte data, address lsbs = 3'b000
// D D D D x x x x 4-byte data, address lsbs = 3'b100
//
// x x x x x x D D 2-byte data, address lsbs = 3'b000
// x x x x D D x x 2-byte data, address lsbs = 3'b010
// ...
// D D x x x x x x 2-byte data, address lsbs = 3'b110
//
// x x x x x x x D 1-byte data, address lsbs = 3'b000
// x x x x x x D x 1-byte data, address lsbs = 3'b001
// ...
// D x x x x x x x 1-byte data, address lsbs = 3'b111
// Only 1 bit/lane is needed for the 'mask' (a.k.a. 'byte-enable' or 'strobe')
// ================================================================
// BSV library imports
import Vector :: *;
// ================================================================
// Expand each bit in 'strobe' to a byte, creating a full-width mask.
function Bit #(TMul #(n,8)) fn_strobe_to_mask (Bit #(n) strobe);
function Bit #(8) fn_bit_j_to_byte_j (Integer j);
return signExtend (strobe [j]);
endfunction
Vector #(n, Bit #(8)) v = genWith (fn_bit_j_to_byte_j);
return pack (v);
endfunction
// ================================================================
// Update an n-byte word taking into account an n-bit strobe
function Bit# (TMul #(n,8)) fn_update_strobed_bytes (Bit# (TMul #(n,8)) old_data,
Bit# (TMul #(n,8)) new_data,
Bit #(n) strobe);
Bit# (TMul #(n,8)) mask = fn_strobe_to_mask (strobe);
return ((old_data & (~ mask)) | (new_data & mask));
endfunction
// ================================================================
// Lane-adjust a data word according to the byte-address and data width
// Args: addr: only bottom few bits are relevant
// width: # of relevant bytes: 1, 2, 4, 8
// data_in: lsb-justified data
// Results: Bool err: misaligned, or bad data_width
// strobe: bit vector showing which lanes are active
// data_out: data shifted to be in-lane
// ----------------
// 32b version
function Tuple3 #(Bool, //
Bit #(4), // strobe
Bit #(32)) // lane-adjusted data
fn_lane_adjust_32b (Bit #(32) addr, Bit #(3) dw, Bit #(32) data);
Bit #(4) strobe = 0;
Bool err = False;
case (dw)
1: case (addr [1:0])
2'b00: begin strobe = 'b_0001; end
2'b01: begin strobe = 'b_0010; data = (data << 8); end
2'b10: begin strobe = 'b_0100; data = (data << 16); end
2'b11: begin strobe = 'b_1000; data = (data << 24); end
endcase
2: case (addr [1:0])
2'b00: begin strobe = 'b_0011; end
2'b10: begin strobe = 'b_1100; data = (data << 16); end
default: err = True;
endcase
4: case (addr [1:0])
2'b00: strobe = 'b_1111;
default: err = True;
endcase
default: err = True;
endcase
return tuple3 (err, strobe, data);
endfunction
// ----------------
// 64b version
function Tuple3 #(Bool, // err: misaligned, or bad data_width
Bit #(8), // strobe
Bit #(64)) // lane-adjusted data
fn_lane_adjust_64b (Bit #(64) addr, Bit #(4) dw, Bit #(64) data);
Bit #(8) strobe = 0;
Bool err = False;
case (dw)
1: case (addr [2:0])
3'b000: begin strobe = 'b_0000_0001; end
3'b001: begin strobe = 'b_0000_0010; data = (data << 8); end
3'b010: begin strobe = 'b_0000_0100; data = (data << 16); end
3'b011: begin strobe = 'b_0000_1000; data = (data << 24); end
3'b100: begin strobe = 'b_0001_0000; data = (data << 32); end
3'b101: begin strobe = 'b_0010_0000; data = (data << 40); end
3'b110: begin strobe = 'b_0100_0000; data = (data << 48); end
3'b111: begin strobe = 'b_1000_0000; data = (data << 56); end
endcase
2: case (addr [2:0])
3'b000: begin strobe = 'b_0000_0011; end
3'b010: begin strobe = 'b_0000_1100; data = (data << 16); end
3'b100: begin strobe = 'b_0011_0000; data = (data << 32); end
3'b110: begin strobe = 'b_1100_0000; data = (data << 48); end
default: err = True;
endcase
3: case (addr [2:0])
3'b000: begin strobe = 'b_0000_1111; end
3'b100: begin strobe = 'b_1111_0000; data = (data << 32); end
default: err = True;
endcase
4: case (addr [2:0])
3'b000: begin strobe = 'b_1111_1111; end
default: err = True;
endcase
default: err = True;
endcase
return tuple3 (err, strobe, data);
endfunction
// ================================================================
// Lane-unadjust a data word according to the byte-address and data width
// ----------------
// 32b version
function Tuple2 #(Bool, // err: misaligned, or bad data_width
Bit #(32)) // lane-unadjusted data
fn_lane_unadjust_32b (Bit #(32) addr, Bit #(3) dw, Bit #(32) data);
Bool err = False;
case (dw)
1: case (addr [1:0])
2'b00: data = (data >> 0);
2'b01: data = (data >> 8);
2'b10: data = (data >> 16);
2'b11: data = (data >> 24);
endcase
2: case (addr [1:0])
2'b00: data = (data >> 0);
2'b10: data = (data >> 16);
default: err = True;
endcase
4: case (addr [1:0])
2'b00: data = (data >> 0);
default: err = True;
endcase
default: err = True;
endcase
return tuple2 (err, data);
endfunction
// ----------------
// 64b version
function Tuple2 #(Bool, // err: misaligned, or bad data_width
Bit #(64)) // lane-unadjusted data
fn_lane_unadjust_64b (Bit #(64) addr, Bit #(4) dw, Bit #(64) data);
Bool err = False;
case (dw)
1: case (addr [2:0])
3'b000: data = (data >> 0);
3'b001: data = (data >> 8);
3'b010: data = (data >> 16);
3'b011: data = (data >> 24);
3'b100: data = (data >> 32);
3'b101: data = (data >> 40);
3'b110: data = (data >> 48);
3'b111: data = (data >> 56);
endcase
2: case (addr [2:0])
3'b000: data = (data >> 0);
3'b010: data = (data >> 16);
3'b100: data = (data >> 32);
3'b110: data = (data >> 48);
default: err = True;
endcase
4: case (addr [2:0])
3'b000: data = (data >> 0);
3'b100: data = (data >> 32);
default: err = True;
endcase
8: case (addr [2:0])
3'b000: data = (data >> 0);
default: err = True;
endcase
default: err = True;
endcase
return tuple2 (err, data);
endfunction
// ================================================================
endpackage