Mod51 Benchmarks & Details
Some REAL WORLD code, (does YOUR controller sort prime numbers ?!) that illustrate the benefits of Modula-2’s low level operations, with the C51 core in embedded control horsepower.
Modula-2 has true NATIVE BOOLEAN types, and BITSET, ROTATE, ELSIF, operators, and has little emphasis on Pointers – all of which adds up to a better ‘fit’ for embedded control than C!.
Also obvious is the high code clarity of Mod51 – one reason it is three times less error prone than C.
How does your Controller / Language combination compare ?
For more language details see Mod51 Summary
Picket Fence DAC is a high speed, precision DAC.
Key Features for a controller to support this are
Boolean Processor
Bit Addressable Bytes
Priority Control on INTERRUPT
Other 8 bit CISC/RISC controllers lack some, or all (!) of these abilities, so do not perform this task efficiently at all.
Mod51 Interrupt – Picket Fence D to A Converter
Picket Fence DAC is a high speed, precision DAC.
Key Features for a controller to support this are
Boolean Processor
Bit Addressable Bytes
Priority Control on INTERRUPT
Other 8 bit CISC/RISC controllers lack some, or all (!) of these abilities, so do not perform this task efficiently at all.
VAR
DACaPIN : BOOLEAN AT P1.6;
DACbPIN : BOOLEAN AT P1.7;
DAC_A, DAC_B, PWM : BYTE BITADDRESSABLE;
DACa,DACb,SaveCY : BOOLEAN;
PeriodCounter : BYTE; (* optional, for slower timebases *)
PROCEDURE (*$Is0*) INTERRUPT_1BH; (* Timer1, samples BIT DATA *)
BEGIN (* ===== Example is for 2 x 8 BIT DAC ================ *)
SaveCY := CY;
INC(PWM); (* roll over does not matter *)
DACaPIN := DACa;
DACbPIN := DACb; (* remove delay-difference in Interrupt as factor *)
(* does ONE of these IF statements ONLY *)
IF PWM.0 THEN (* 128 Pickets, odd numbers *)
DACa := DAC_A.7;
DACb := DAC_B.7;
ELSIF PWM.1 THEN (* 64 Pickets xxxx_xx10 *)
DACa := DAC_A.6;
DACb := DAC_B.6;
ELSIF PWM.2 THEN (* 32 Pickets xxxx_x100 *)
DACa := DAC_A.5;
DACb := DAC_B.5;
ELSIF PWM.3 THEN (* 16 Pickets xxxx_1000 *)
DACa := DAC_A.4;
DACb := DAC_B.4;
ELSIF PWM.4 THEN (* 8 Pickets xxx1_0000 *)
DACa := DAC_A.3;
DACb := DAC_B.3;
ELSIF PWM.5 THEN (* 4 Pickets xx10_0000 *)
DACa := DAC_A.2;
DACb := DAC_B.2;
ELSIF PWM.6 THEN (* 2 Pickets x010_0000 *)
DACa := DAC_A.1;
DACb := DAC_B.1;
ELSIF PWM.7 THEN (* 1 Pickets 1000_0000 *)
DACa := DAC_A.0;
DACb := DAC_B.0;
ELSE (* All LOW, /256 times INT possible.. *)
DACa := FALSE;
DACb := FALSE;
INC(PeriodCounter);
END;
CY := SaveCY;
END INTERRUPT_1BH; (* core, 129 bytes, for 2 x 8 bit *)
Mod51 Interrupt / Delta Modulation A to D Converter
Delta Modulation ADC – This runs as a 7 bit delta modulator, for linear ADC. Shows INTERRUPT, and BOOLEAN support. C51 is very good at this type of work – other cores suffer.
Note: The C51 can code this without any PUSH/POP
VAR
DELTASIG_Res,
DELTASIG_Ctr : BYTE BITADDRESSABLE;
DACaPIN : BOOLEAN AT P3.7;
Comp : BOOLEAN AT P3.6; (* 89C2051 family *)
PeriodCounter : BYTE BITADDRESSABLE; (* For slower timebases *)
PROCEDURE (*$Is0*) INTERRUPT_0BH; (* Timer0, fast pickets *)
BEGIN
IF Comp THEN
DACaPIN := FALSE;
ELSE
DACaPIN := TRUE;
END;
IF DELTASIG_Ctr.7 THEN (* End of cycle, 7 bits... *)
DeltaValue := DELTASIG_Res;
DELTASIG_Res := DELTASIG_Res AND 00H;
DELTASIG_Ctr := 0FFH; (* Start next cycle *)
INC (PeriodCounter); (* For lower timebases *)
ChkDSRatePin := NOT ChkDSRatePin; (* Optional CRO Test *)
ELSIF DACaPIN THEN
INC (DELTASIG_Res); (* Measure averages.. *)
END;
INC (DELTASIG_Ctr); (* Roll over does not matter *)
END INTERRUPT_0BH; (* Core, 35 bytes *)
Mod51 – Real Time 24 Hour Clock
Looks like simple code – but other compilers/cores have done this with CALLS to subroutines.
This benchmark is a good test of DATA memory access, which the C51 performs very well – RISC cores like AVR does poorly.
VAR Tenths,Seconds,Minutes,Hours : SHORTCARD; Tick10 : BOOLEAN; (* Set inside an Interrupt, with 100mS sub-loop *) PROCEDURE ClockA; (* 24 Hours, so 23:59:59:09 ticks over to 00:00:00:00 *) BEGIN IF NOT Tick10 THEN RETURN; END; (* Not my event, return *) Tick10 := FALSE; INC(Tenths); IF Tenths = 10 THEN Tenths := 0; INC(Seconds); IF Seconds = 60 THEN Seconds := 0; INC(Minutes); IF Minutes = 60 THEN Minutes := 0; INC(Hours); IF Hours = 24 THEN Hours := 0; END; END; END; END; END ClockA; (* 51 bytes *)
Mod51 Bit Stream Support
The BITSET type in Mod51 allows ARRAY of BITSET to implement array of bit functions, in the C51 core.
With a Single variable, you can index any BIT in an array of BITSET typed Bytes – these can be in IDATA.
This example shows INTERRUPT, and BOOLEAN support, and the excellant coding of Modula-2.
This code does Bounded WINDOW bit pulse width tests, and stores valid bits into the RxCODE array, finally setting NewFrame if all BITS are valid, and a Pause is seen.
The C51/Mod51 pairing is very good at this type of work – other cores suffer.
VAR RxCODE : ARRAY[0..2] OF BITSET; (* 24 Bits, in 'array' *) RxCtr : BYTE; NewFrame : BOOLEAN; CONST FrameBITS = 24; OneAVGE = 3CH; (* or Whatever you measure *) ZeroAVGE = 2FH; OneMIN = OneAVGE - OneAVGE DIV 4; OneMAX = OneAVGE + OneAVGE DIV 4; ZeroMIN = ZeroAVGE - ZeroAVGE DIV 4; ZeroMAX = ZeroAVGE + ZeroAVGE DIV 4; PROCEDURE (*$IS3*) INTERRUPT_03H; (* INT0 ==\__ = P3.2 *) BEGIN IF TF0 THEN (* Is FIRST / Last pulse == SYNC and FRAME decison Code *) TF0 := FALSE; IF RxCtr = FrameBITS THEN (* end of pulses, MUST have had a VALID frame ! *) NewFrame := TRUE; ELSE (* start of pulse learning *) RxCODE[0] := {}; (* Load with 24 Zeros *) RxCODE[1] := {}; RxCODE[2] := {}; END; RxCtr := 0; ELSIF RxCtr < 24 THEN (* is Bit Picking Code ..... *) CASE TL0 OF | OneMIN..OneMAX : INCL(RxCODE[RxCtr >> 3],RxCtr); (* SET single Bit, in ONE byte *) | ZeroMIN..ZeroMAX : (* default is a Zero *) ELSE (* bad Bit Time Width value, so reset *) TF0 := TRUE; (* catch Reset, next pass ? *) RxCtr := 0; END; INC(RxCtr); END; END INTERRUPT_03H; (* just 93 bytes ! *) (* Most of the 'work' is done by the single INCL statement INCL(BitSet,BitNum); -> SETs (BitNum MOD 8) in BYTE variable BitSet BitSet can be an ARRAY ( as above ), and BitNum can be a CONST, or variable. BitNum > 7 is also legal, Mod51 wraps this to 0..7 *)