From daff1754b215d579e1e1413554120a86f624bcde Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Mon, 23 May 2022 21:10:29 -0500 Subject: [PATCH] Make volatile loads from IO/softswitches access exactly the byte(s) specified. Previously, one-byte loads were typically done by reading a 16-bit value and then masking off the upper 8 bits. This is a problem when accessing softswitches or slot IO locations, because reading the subsequent byte may have some undesired effect. Now, ORCA/C will do an 8-bit read for such cases, if the volatile qualifier is used. There were also a couple optimizations that could occasionally result in not all the bytes of a larger value actually being read. These are now disabled for volatile loads that may access softswitches or IO. These changes should make ORCA/C more suitable for writing low-level software like device drivers. --- CGI.Comments | 3 ++- DAG.pas | 6 ++++-- Expression.pas | 22 +++++++++++++--------- Gen.pas | 23 +++++++++++++++++++---- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/CGI.Comments b/CGI.Comments index 85164dc..1ce23d0 100644 --- a/CGI.Comments +++ b/CGI.Comments @@ -349,11 +349,12 @@ { } { pc_ind - load indirect } { } -{ Gen1t (pc_ind, disp, type) } +{ Gen2t (pc_ind, volatile, disp, type) } { } { A value of type TYPE is loaded from DISP bytes past the } { address that is on the evaluation stack. The address is } { removed from the stack and replaced with the value. } +{ VOLATILE is non-zero for a volatile load, or 0 otherwise. } { } { } { pc_ior - logical or } diff --git a/DAG.pas b/DAG.pas index 3e9721a..3c46e15 100644 --- a/DAG.pas +++ b/DAG.pas @@ -1414,7 +1414,8 @@ case op^.opcode of {check for optimizations of this node} PeepHoleOptimization(opv); end; {if} end {else if} - else if op^.left^.opcode in [pc_lod,pc_ldo,pc_ind] then begin + else if (op^.left^.opcode in [pc_lod,pc_ldo]) or + ((op^.left^.opcode = pc_ind) and (op^.left^.r = 0)) then begin if fromtype.optype in [cgWord,cgUWord] then if totype.optype in [cgByte,cgUByte,cgWord,cgUWord] then begin op^.left^.optype := totype.optype; @@ -1452,7 +1453,8 @@ case op^.opcode of {check for optimizations of this node} with op^.left^ do if opcode in [pc_slr,pc_vsr] then if right^.opcode = pc_ldc then - if left^.opcode in [pc_lod,pc_ldo,pc_ind] then begin + if (left^.opcode in [pc_lod,pc_ldo]) or + ((left^.opcode = pc_ind) and (left^.r = 0)) then begin lq := right^.lval; if long(lq).msw = 0 then if long(lq).lsw in [8,16,24] then begin diff --git a/Expression.pas b/Expression.pas index cb8928c..4b28bb7 100644 --- a/Expression.pas +++ b/Expression.pas @@ -2756,6 +2756,7 @@ var et: baseTypeEnum; {temp storage for a base type} i: integer; {loop variable} isString: boolean; {was the ? : a string?} + isVolatile: boolean; {is this a volatile op?} lType: typePtr; {type of operands} kind: typeKind; {temp type kind} size: longint; {size of an array element} @@ -3146,7 +3147,7 @@ var Gen2t(pc_lbf, bitDisp, bitSize, tp); end {if} else - Gen1t(pc_ind, 0, tp); + Gen2t(pc_ind, ord(tqVolatile in expressionType^.qualifiers), 0, tp); if pc_l in [pc_lli,pc_lld] then if expressionType^.cType in [ctBool,ctFloat,ctDouble,ctLongDouble, ctComp] then begin @@ -3724,6 +3725,7 @@ case tree^.token.kind of Gen2t(pc_lod, t1, 0, cgULong); Gen2t(pc_lod, t1, 0, cgULong); lType := expressionType^.pType; + isVolatile := tqVolatile in lType^.qualifiers; if isBitField then begin if unsigned then Gen2t(pc_lbu, bitDisp, bitSize, lType^.baseType) @@ -3731,9 +3733,9 @@ case tree^.token.kind of Gen2t(pc_lbf, bitDisp, bitSize, lType^.baseType); end {if} else if lType^.kind = pointerType then - Gen1t(pc_ind, 0, cgULong) + Gen2t(pc_ind, ord(isVolatile), 0, cgULong) else - Gen1t(pc_ind, 0, lType^.baseType); + Gen2t(pc_ind, ord(isVolatile), 0, lType^.baseType); end; {else} if tqConst in lType^.qualifiers then Error(93); @@ -4481,13 +4483,14 @@ case tree^.token.kind of else if lType^.kind = pointerType then lType := lType^.pType; expressionType := lType; + isVolatile := tqVolatile in lType^.qualifiers; if lType^.kind = scalarType then if lType^.baseType = cgVoid then - Gen1t(pc_ind, 0, cgULong) + Gen2t(pc_ind, ord(isVolatile), 0, cgULong) else - Gen1t(pc_ind, 0, lType^.baseType) + Gen2t(pc_ind, ord(isVolatile), 0, lType^.baseType) else if lType^.kind = pointerType then - Gen1t(pc_ind, 0, cgULong) + Gen2t(pc_ind, ord(isVolatile), 0, cgULong) else if not ((lType^.kind in [functionType,arrayType,structType,unionType]) or ((lType^.kind = definedType) and {handle const struct/union} @@ -4513,6 +4516,7 @@ case tree^.token.kind of size := 0; end; {else} kind := expressionType^.kind; + isVolatile := tqVolatile in expressionType^.qualifiers; if kind = scalarType then begin et := expressionType^.baseType; if isBitField then begin @@ -4524,12 +4528,12 @@ case tree^.token.kind of Gen2t(pc_lbf, bitDisp, bitSize, et); end {if} else - Gen1t(pc_ind, long(size).lsw, et); + Gen2t(pc_ind, ord(isVolatile), long(size).lsw, et); end {if} else if kind = pointerType then - Gen1t(pc_ind, long(size).lsw, cgULong) + Gen2t(pc_ind, ord(isVolatile), long(size).lsw, cgULong) else if kind = enumType then - Gen1t(pc_ind, long(size).lsw, cgWord) + Gen2t(pc_ind, ord(isVolatile), long(size).lsw, cgWord) else if size <> 0 then Gen1t(pc_inc, long(size).lsw, cgULong); end {if} diff --git a/Gen.pas b/Gen.pas index bbd5c24..0884a48 100644 --- a/Gen.pas +++ b/Gen.pas @@ -2923,6 +2923,7 @@ var lQuad: quadType; {requested quad address type} optype: baseTypeEnum; {op^.optype} q: integer; {op^.q} + volatileByte: boolean; {is this a volatile byte access?} begin {GenInd} optype := op^.optype; @@ -3068,22 +3069,36 @@ case optype of cgByte,cgUByte,cgWord,cgUWord: begin GetPointer(op^.left); if gLong.where = inPointer then begin - if q = 0 then + volatileByte := (op^.r <> 0) and (optype in [cgByte,cgUByte]); + if q = 0 then begin + if volatileByte then + GenNative(m_sep, immediate, 32, nil, 0); if gLong.fixedDisp then GenNative(m_lda_indl, direct, gLong.disp, nil, 0) else - GenNative(m_lda_indly, direct, gLong.disp, nil, 0) + GenNative(m_lda_indly, direct, gLong.disp, nil, 0); + if volatileByte then + GenNative(m_rep, immediate, 32, nil, 0); + end {if} else if gLong.fixedDisp then begin + if volatileByte then + GenNative(m_sep, immediate, 32, nil, 0); GenNative(m_ldy_imm, immediate, q, nil, 0); - GenNative(m_lda_indly, direct, gLong.disp, nil, 0) + GenNative(m_lda_indly, direct, gLong.disp, nil, 0); + if volatileByte then + GenNative(m_rep, immediate, 32, nil, 0); end {if} else begin GenImplied(m_tya); GenImplied(m_clc); GenNative(m_adc_imm, immediate, q, nil, 0); GenImplied(m_tay); - GenNative(m_lda_indly, direct, gLong.disp, nil, 0) + if volatileByte then + GenNative(m_sep, immediate, 32, nil, 0); + GenNative(m_lda_indly, direct, gLong.disp, nil, 0); + if volatileByte then + GenNative(m_rep, immediate, 32, nil, 0); end; {else} end {if} else if gLong.where = localAddress then begin