219 lines
8.0 KiB
Plaintext
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
|