From 8492136abdec6c254c923e2b74a89658d09a5039 Mon Sep 17 00:00:00 2001 From: jon Date: Tue, 9 Jun 2020 17:39:36 +0100 Subject: [PATCH] Attempt to convert more functions in the MMIO platform to respect the alignment of the original data. Also eliminate the call to the reimplementation of the AMO functions. (One call was already converted to use the common function, and I've now converted the other.) It's honestly unknown how much of this works, but it's more likely to work than what was previously implemented, I think, given that the previou implementation was based on some basic misconceptions concerning data alignment. --- src_Core/CPU/MMIOPlatform.bsv | 135 ++++++---------------------------- 1 file changed, 24 insertions(+), 111 deletions(-) diff --git a/src_Core/CPU/MMIOPlatform.bsv b/src_Core/CPU/MMIOPlatform.bsv index c69ac31..6381749 100644 --- a/src_Core/CPU/MMIOPlatform.bsv +++ b/src_Core/CPU/MMIOPlatform.bsv @@ -110,94 +110,6 @@ function Bit #(64) fn_extract_and_extend_bytes (Bit #(2) sz, Bit #(64) byte_addr return result; endfunction -// ================================================================ -// Update relevant bytes of store-value. -// The bytes of interest are offset according to LSBs of addr. -// Arguments: -// - a RISC-V LD/ST size (encoding B, H, W, or D) -// - a byte-address -// - an amo result (relevant bytes are in lower-order bits) -// - original store-val -// result: -// - store-val with relevant byte(s) updated - -function Bit #(64) fn_update_bytes (Bit #(2) sz, Bit #(64) byte_addr, Bit #(64) value, Bit #(64) st_val); - Bit #(64) result = 0; - Bit #(3) addr_lsbs = byte_addr [2:0]; - - case (sz) - sz_B: case (addr_lsbs) - 'h0: result = { st_val [63:8], value [7:0] }; - 'h1: result = { st_val [63:16], value [7:0], st_val [7:0] }; - 'h2: result = { st_val [63:24], value [7:0], st_val [15:0] }; - 'h3: result = { st_val [63:32], value [7:0], st_val [23:0] }; - 'h4: result = { st_val [63:40], value [7:0], st_val [31:0] }; - 'h5: result = { st_val [63:48], value [7:0], st_val [39:0] }; - 'h6: result = { st_val [63:56], value [7:0], st_val [47:0] }; - 'h7: result = { value [7:0], st_val [55:0] }; - endcase - - sz_H: case (addr_lsbs) - 'h0: result = { st_val [63:16], value [15:0] }; - 'h2: result = { st_val [63:32], value [15:0], st_val [15:0] }; - 'h4: result = { st_val [63:48], value [15:0], st_val [31:0] }; - 'h6: result = { value [15:0], st_val [47:0] }; - endcase - - sz_W: case (addr_lsbs) - 'h0: result = { st_val [63:32], value [31:0] }; - 'h4: result = { value [31:0], st_val [31:0] }; - endcase - - sz_D: case (addr_lsbs) // D - 'h0: result = st_val; - endcase - endcase - return result; -endfunction - -// ================================================================ -// AMO op function -// Extracts the relevant bytes from ld_val and st_val, -// Performs the AMO op, -// Updates the relevant bytes of st_val. - -function Bit #(64) fn_amo_op (Bit #(2) sz, // encodes data size (.W or .D) - AmoFunc amofunc, // encodes the AMO op - Bit #(64) addr, // lsbs indicate which 32b W in 64b D (.W) - Bit #(64) ld_val, // 64b value loaded from mem - Bit #(64) st_val); // 64b value from CPU reg Rs2 - // Extract relevant bytes of ld_val and st_val - Bit #(64) w1 = fn_extract_and_extend_bytes (sz, addr, ld_val); - Bit #(64) w2 = fn_extract_and_extend_bytes (sz, addr, st_val); - - // Do AMO op - Int #(64) i1 = unpack (w1); // Signed, for signed ops - Int #(64) i2 = unpack (w2); // Signed, for signed ops - if (sz == 2'b10) begin - // 32-bit word - w1 = zeroExtend (w1 [31:0]); - w2 = zeroExtend (w2 [31:0]); - i1 = unpack (signExtend (w1 [31:0])); - i2 = unpack (signExtend (w2 [31:0])); - end - Bit #(64) op_result = ?; - case (amofunc) - Swap: op_result = w2; - Add: op_result = pack (i1 + i2); - Xor: op_result = w1 ^ w2; - And: op_result = w1 & w2; - Or: op_result = w1 | w2; - Minu: op_result = ((w1 < w2) ? w1 : w2); - Maxu: op_result = ((w1 > w2) ? w1 : w2); - Min: op_result = ((i1 < i2) ? w1 : w2); - Max: op_result = ((i1 > i2) ? w1 : w2); - endcase - - // Update relevant bytes of st_val - return fn_update_bytes (sz, addr, op_result, st_val); -endfunction: fn_amo_op - // ================================================================ // MMIO logic at platform (MMIOPlatform) // XXX Currently all MMIO requests and posts of timer interrupts are handled @@ -455,10 +367,12 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores, end end else if(reqFunc matches tagged Amo .amoFunc) begin + Tuple2#(Bit#(32), Bit#(4)) amo_req = fromMemTaggedDataSelect(reqData, pack(reqBE)); + match {.amo_req_data, .amo_req_be} = amo_req; // AMO req: should only access MSIP of one core. Thus, we always // treat the accessed core as the lower core to save the shift (AMO // resp is different from load that valid data is already shifted - // to LSBs). Besides, we only use the lower 32 bits of reqData. + // to LSBs). Besides, we only use 32 bits reqData. if(lower_en && upper_en) begin state <= SelectReq; cores[reqCore].pRs.enq(DataAccess (MMIODataPRs { @@ -473,7 +387,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores, cores[lower_core].pRq.enq(MMIOPRq { target: MSIP, func: reqFunc, - data: fromMemTaggedData(reqData) + data: amo_req_data }); waitLowerMSIPCRs <= Valid (lower_core); waitUpperMSIPCRs <= Invalid; @@ -483,7 +397,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores, cores[upper_core].pRq.enq(MMIOPRq { target: MSIP, func: reqFunc, - data: fromMemTaggedData(reqData) + data: amo_req_data }); waitLowerMSIPCRs <= Valid (upper_core); waitUpperMSIPCRs <= Invalid; @@ -554,30 +468,22 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores, endrule function Data getWriteData(Data orig); + Tuple2#(Data, Bit#(DataBytes)) wr = fromMemTaggedDataSelect(reqData, pack(reqBE)); + match {.wr_data, .wr_be} = wr; if(reqFunc matches tagged Amo .amoFunc) begin // amo let amoInst = AmoInst { func: amoFunc, - width: reqBE[4] && reqBE[0] ? DWord : Word, + width: wr_be[4]==1 && wr_be[0]==1 ? DWord : Word, aq: False, rl: False }; - let res = amoExec(amoInst, {0, pack(reqBE[4] && !reqBE[0])}, - toMemTaggedData(orig), reqData); + let res = amoExec(amoInst, {0, pack(wr_be[4]==1 && wr_be[0]!=1)}, + toMemTaggedData(orig), toMemTaggedData(wr_data)); return res.data[0]; end - else begin - // normal store - Vector#(DataBytes, Bit#(8)) data = unpack(orig); - Vector#(DataBytes, Bit#(8)) wrVec = fromMemTaggedData(reqData); - for(Integer i = 0; i < valueof(DataBytes); i = i+1) begin - if(reqBE[i]) begin - data[i] = wrVec[i]; - end - end - return pack(data); - end + else return mergeDataBE(orig, wr_data, wr_be); endfunction function Data getAmoResp(Data orig); @@ -950,14 +856,21 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores, state <= SelectReq; end else begin + MemTaggedData ld_val = dprs.data; // Do the AMO op on the loaded value and the store value - let ld_val = dprs.data; - let new_st_val = fn_amo_op ( reqSz, reqAmofunc, addr - , fromMemTaggedData(ld_val) - , fromMemTaggedData(reqData)); + function Bool pred(Bool b) = b; + let set_bes = countIf(pred, reqBE); + let amoInst = AmoInst { + func: reqAmofunc, + width: (set_bes > 4) ? DWord : Word, + aq: False, + rl: False + }; + let new_st_val = amoExec(amoInst, addr[3:2], + ld_val, reqData); // Write back new st_val to fabric - let req = MMIOCRq {addr:addr, func:tagged St, byteEn:reqBE, data:toMemTaggedDataSelect(new_st_val, addr)}; + let req = MMIOCRq {addr:addr, func:tagged St, byteEn:reqBE, data: new_st_val}; mmio_fabric_adapter_core_side.request.put (req); let prs = tagged DataAccess (MMIODataPRs { valid: True, data: ld_val }); @@ -1031,7 +944,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores, end // View Data as a vector of instructions - Vector#(MemDataSzInst, Instruction) instVec = fromMemTaggedData(dprs.data); + Vector#(MemDataSzInst, Instruction) instVec = unpack(pack(dprs.data.data)); // extract inst from resp data Instruction inst = instVec[instSel]; // check whether we are done or not