Sign In

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
*)

Related Posts