1. There could be a way to intentionally overlap variables, as it is done in Borland compilers:
Code: Select all
var
myWord: Word;
myBytes: array[0..1] of Byte; absolute myWord;
Code: Select all
var
myWord: Word;
myBytes: array[0..1] of Byte; absolute @myWord; // Notice the @
2. Since procedure and function parameters are actually static variables, nothing prevents the compiler from allowing them to be at an absolute address:
Code: Select all
unit Multiplexer;
// This unit manages 64 digital outputs using 12 I/O lines:
// - a 3-to-8 decoder is connected to PORTC<2:0>
// - the decoder outputs, together with (inverted) PORTC<3>,
// enable 8 8-bit non-inverting latches which drive the actual outputs
// - PORTD acts as a data bus; the state of PORTD lines is latched
// by selecting an output group via PORTC<2:0> and lowering PORTC<3>
const
gc_Multiplexer_PortCount = 8;
var
m_PortImage: array[0..gc_Multiplexer_PortCount - 1] of Byte;
m_Port : Byte;
m_Value : Byte;
// This is called during initialization
procedure Multiplexer_Initialize;
var
i: Byte;
begin
TRISC.0 := 0;
TRISC.1 := 0;
TRISC.2 := 0;
TRISC.3 := 0;
TRISD := 0;
PORTC.3 := 1; // Latch enable, active low
for i := 0 to gc_Multiplexer_PortCount - 1 do begin
m_PortImage[i] := 0;
end;
end;
// Write a group of 8 outputs
// NOTE: No check whatsoever is made on parameter values
procedure Multiplexer_Write(_Port: Byte absolute m_Port; _Value: Byte absolute m_Value);
begin
m_PortImage[_Port] := _Value;
PORTC := (LATC and $F8) or Port; // Put address on PORTC<2:0>
PORTD := _Value; // Put value on PORTD
PORTC.3 := 0; // Enable latches
PORTC.3 := 1; // Disable latches
// Necessary NOPs were intentionally omitted :P
end;
// Write a group of 8 outputs only if its value has not changed
// This *looks* useless, but actual multiplexing is often more complex
// than the one imagined here and writing on an output port may be
// rather time-consuming, especially if done lots of times in an ISR.
procedure Multiplexer_WriteIfChanged(_Port: Byte absolute m_Port; _Value: Byte absolute m_Value);
begin
if _Value = m_PortImage[_Port] then Exit;
// Parameters are already in place!
asm
BRA _Multiplexer_Write
end;
end;
// Change only the bits specified by _Mask
procedure Multiplexer_MaskedWrite(_Port: Byte absolute m_Port; _Mask: Byte; _Value: Byte absolute m_Value);
begin
_Value := (_Value and _Mask) or (m_PortImage[_Port] and not _Mask);
// Parameters are already in place!
asm
BRA _Multiplexer_Write
end;
end;
// Remind me what I wrote to a port
function Multiplexer_ReadBack(_Port: Byte absolute m_Port): Byte;
begin
Result := m_PortImage[_Port];
end;
end.