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.
This commit is contained in:
Stephen Heumann 2022-05-23 21:10:29 -05:00
parent 21f266c5df
commit daff1754b2
4 changed files with 38 additions and 16 deletions

View File

@ -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 }

View File

@ -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

View File

@ -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}

23
Gen.pas
View File

@ -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