Lezing ByteForth voor AVR processoren


De AVR cpu  (1)

    - Cpu opbouw
    - Positieve aspecten
    - Negatieve aspecten
    - AVR uitvoeringen


ByteForth voor de AVR

    - Assembler
    - Disassembler
    - Simulator
    - ISP Programmer
    - Interactieve compiler
    - Verschillen met huidige 8051 ByteForth




AVR cpu schema (2 & 3)




AVR soorten (4)

Type        Pins    Flash   RAM     EEPROM  I/O  Timers     Brownout    ADC
----------------------------------------------------------------------------
ATtiny22    8       2 KB    128     128     5    Een          ja        Nee
AT90S2313   20      2 KB    128     128     15   Twee         Nee       Nee
AT90S2323   8       2 KB    128     128     3    Een          Nee       Nee
AT90S4433   28      4 KB    128     256     20   Twee         Ja        Ja
AT90S8515   44      8 KB    256     256     32   Twee         Nee       Nee
AT90S8535   44      8 KB    256     256     32   Drie         Nee       Ja
ATmega161   44      16 KB   1024    512     35   Drie         Ja        Nee
ATmega603   64      64 KB   4096    2048    48   Vier         ?         Ja

Dit is slechts een kort overzicht van deze controller reeks. Op klanten
specificatie kunnen er diverse uitvoeringen gemaakt worden met b.v.
extra I2C bus, CAN bus, etc.




AVR ByteForth geheugen indeling (5)

    - Registers
        - Laad constante(n) en extra accu   R0 met LPM, instructie
        - ByteForth systeem                 R1 highlevel LOOP teller
        - Bitvariabelen                     Met var's in R2 t/m R15
        - Register variabelen               Met bitvariabelen in R2 t/m R15
        - Accus voor code definities        10 bytes R16 t/m R25
        - Stackpointers X, Y, Z             Hoogste 6 bytes R26 t/m R31
                                            X = Data Stack Pointer
                                            Y = Variable Base Pointer
                                            Z = Vrij voor locals, SLITERAL,
                                                DOES>, INLINE$ & EXECUTE

    - I/O-registers                         Als gedefinieerd door de
                                            fabrikant van SFR-0 t/m SFR-63

    - RAM
        - De reg. en de I/O-reg.            Ook op de RAM adressen 0 t/m 95
        - Datastack                         Adres 127 t/m 96
        - Localstack                        Adres 128 omhoog onder RSP
        - Returnstack                       Van max. adres 255 naar beneden
        - Variabelen                        Boven returnstack tot RAMTOP of
                                            maximaal 64 stuks.
        - Variables                         Arrays beginnen op RAMTOP deze
                                            groeien omlaag naar de variabelen
        - Getal conversie                   Via array in het ByteForth systeem

    - ROM
        - Interrupt vectoren                0 t/m xxx
        - Initialisatie tabel               xxx t/m yyy
        - Programma                         yyy t/m ROMTOP




Code voorbeelden (6)

$C1 MACRO DUP            ( x -- x x )   \ Macros "dupe"
    R16 X LD,
    -X R16 ST,
    RET,
END-CODE

$01 MACRO OVER           ( x1 x2 -- x1 x2 x1 ) \ Macros
    XL 1 ADIW,
    R16 X LD,
    XL 1 SBIW,
    -X R16 ST,
    RET,
END-CODE

$21 MACRO +              ( x1 x2 -- x3 ) \ Macros "plus"
    R16 X+ LD,
    R17 X+ LD,
    R16 R17 ADD,
    -X R16 ST,
    RET,
END-CODE

$01 MACRO @              ( addr --- x ) \ Macros "fetch"
    ZH X+ LD,
    ZL X+ LD,
    R16 Z LD,
    -X R16 ST,
    RET,
END-CODE

$01 MACRO ROM@           ( rom-addr -- x )    \ Macros "rom-fetch"
    ZH X+ LD,                           \ High byte to dptr high
    ZL X+ LD,                           \ Low byte to dptr low
    LPM,                                \ Read ROM byte
    R16 R0 MOV,                         \ Move to accu
    -X R16 ST,
    RET,
END-CODE

: VARIABLE          ( "name" -- addr )  \ Cross
    VA VE > 20 ?ERROR                   \ Within valid RAM space ?
    CREATE  VA ,  1  DUP ,  +TO VA  IMMEDIATE
    DOES>   @  POSTPONE LITERAL         \ Variable offset on stack
            ;                           \ at runtime ! ( as usual ).

: VARIABLES         ( +n "name" -- addr | -- x )    \ Cross
    vas OVER -  va vp +  U< 20 ?ERROR   \ Want too much RAM ?
    CREATE  DUP NEGATE  +TO vas  vas ,  ,  IMMEDIATE 
    vas vp -  ve 1+  < IF  vas vp - 1-  TO ve  THEN
    DOES>   @  XFLYER  >R               \ Variable address on stack
        POPA,                           \ 14 bytes code
        R17 R16 MOV,
        R16 CLR,
        R17 R@ NEGATE SUBI,
        R16 R> NEGATE >< SBCI,
        2PUSH,
        ;




De AVR Assembler (7)

(  1 MODES Rn )      3 MODES X           4 MODES X+
   5 MODES -X        7 MODES Y+          8 MODES -Y
   9 MODES [Y]      11 MODES Z+         12 MODES -Z
  13 MODES [Z]

' -REG,     $900C   $13                  \ <Rn> X LD,
' -REG,     $900D   $14                  \ <Rn> X+ LD,
' -REG,     $900E   $15                  \ <Rn> -X LD,
' -REG,     $9009   $17                  \ <Rn> Y+ LD,
' -REG,     $900A   $18                  \ <Rn> -Y LD,
' LD-R+DIS, $8008   $19                  \ <Rn> +n [Y] LD,
' -REG,     $9001   $1B                  \ <Rn> Z+ LD,
' -REG,     $9002   $1C                  \ <Rn> -Z LD,
' LDDZ,     $8000   $1D   9 2MODES LD,   \ <Rn> +n [Z] LD,

' CONST,    $E000   $10   1 2MODES LDI,  \ <Rn> k LDI,

: SER,      $FF LDI, ;                   \ <Rn> SER,




Disassembly onderzoek (8 & 9)

Disassembler, simulator structuur onderzoek. Een eerste selectie wordt
gedaan via de hoogste 4 bits van een 16-bits opcode veld. Achter een
opcode staat soms een '&' deze geeft een opcode alias aan!!

s = source register
d = destination register
k = konstant getal
b = bitnummer
a = adres
p = poortadres
x = betekent maakt niet uit wat er staat

          xx    xxxx    xxxx    ( Bij NOP zijn alle x-en nullen )  
0000    0000    0000    0000    NOP
0000    01sd    dddd    ssss    CPC
0000    10sd    dddd    ssss    SBC
0000    11sd    dddd    ssss    ADD  & LSL

0001    00sd    dddd    ssss    CPSE
0001    01sd    dddd    ssss    CP
0001    10sd    dddd    ssss    SUB
0001    11sd    dddd    ssss    ADC  & ROL

0010    00sd    dddd    ssss    AND  & TST
0010    01sd    dddd    ssss    EOR  & CLR
0010    10sd    dddd    ssss    OR
0010    11sd    dddd    ssss    MOV

0011    kkkk    dddd    kkkk    CPI
0100    kkkk    dddd    kkkk    SBCI
0101    kkkk    dddd    kkkk    SUBI
0110    kkkk    dddd    kkkk    ORI  & SBR
0111    kkkk    dddd    kkkk    ANDI & CBR

10k0                            ( basis patroon )
1000    kk0d    dddd    0kkk    LD Rd,Z+k  (0-31)
1000    kk0d    dddd    1kkk    LD Rd,Y+k  (0-31)
1000    kk1s    ssss    0kkk    ST Z+k,Rd  (0-31)
1000    kk1s    ssss    1kkk    ST Y+k,Rd  (0-31)

1001    000d    dddd    0000    LDS  Extra cel: aaaa    aaaa    aaaa    aaaa
1001    000d    dddd    0001    LD Rd,Z+
1001    000d    dddd    0010    LD Rd,-Z
1001    000d    dddd    1001    LD Rd,Y+
1001    000d    dddd    1010    LD Rd,-Y
1001    000d    dddd    1100    LD Rd,X
1001    000d    dddd    1101    LD Rd,X+
1001    000d    dddd    1110    LD Rd,-X
1001    000d    dddd    1111    POP

1001    001s    ssss    0000    STS  Extra cel: aaaa    aaaa    aaaa    aaaa
1001    001s    ssss    0001    ST Z+,Rd
1001    001s    ssss    0010    ST -Z,Rd
1001    001s    ssss    1001    ST Y+,Rd
1001    001s    ssss    1010    ST -Y,Rd
1001    001s    ssss    1100    ST X,Rd
1001    001s    ssss    1101    ST X+,Rd
1001    001s    ssss    1110    ST -X,Rd
1001    001s    ssss    1111    PUSH





1001    010d    dddd    0000    COM
1001    010d    dddd    0001    NEG
1001    010d    dddd    0010    SWAP
1001    010d    dddd    0011    INC
1001    010d    dddd    0101    ASR
1001    010d    dddd    0110    LSR
1001    010d    dddd    0111    ROR

1001    0100    0bbb    1000    BSET
1001    0100    1bbb    1000    BCLR
1001    0101    0xx0    1000    RET
1001    0101    0xx1    1000    RETI
1001    0101    100x    1000    SLEEP
1001    0101    101x    1000    WDR
1001    0101    110x    1000    LPM

1001    0100    xxxx    1001    IJMP
1001    0101    xxxx    1001    ICALL

1001    010d    dddd    1010    DEC

( Niet op 8515 )        xxxa    ( basis patroon )
1001    010a    aaaa    1100    JMP   Extra cel: aaaa    aaaa    aaaa    aaaa
1001    010a    aaaa    1101    JMP   Extra cel: aaaa    aaaa    aaaa    aaaa
1001    010a    aaaa    1110    CALL  Extra cel: aaaa    aaaa    aaaa    aaaa
1001    010a    aaaa    1111    CALL  Extra cel: aaaa    aaaa    aaaa    aaaa

1001    0110    kkdd    kkkk    ADIW
1001    0111    kkdd    kkkk    SBIW
1001    1000    pppp    pbbb    CBI
1001    1001    pppp    pbbb    SBIC
1001    1010    pppp    pbbb    SBI
1001    1011    pppp    pbbb    SBIS

( Niet op 8515 en lager aanwezig )
        11sd                    ( basis patroon )
1001    110d    dddd    ssss    MUL
1001    111d    dddd    ssss    MUL

10k0                            ( basis patroon )
1010    kk0d    dddd    0kkk    LD Rd,Z+k  (32-64)  & Rd,Z
1010    kk0d    dddd    1kkk    LD Rd,Y+k  (32-64)  & Rd,Y
1010    kk1s    ssss    0kkk    ST Z+k,Rd  (32-64)  & Z,Rd
1010    kk1s    ssss    1kkk    ST Y+k,Rd  (32-64)  & Y,Rd

1011    0ppd    dddd    pppp    IN
1011    1pps    ssss    pppp    OUT

1100    kkkk    kkkk    kkkk    RJMP
1101    kkkk    kkkk    kkkk    RCALL
1110    kkkk    dddd    kkkkk   LDI  & SER

1111    00kk    kkkk    kbbb    BRBS
1111    01kk    kkkk    kbbb    BRBC
1111    100d    dddd    xbbb    BLD  ( Alleen deze x is 0 in het databoek )
1111    101s    ssss    xbbb    BST
1111    110s    ssss    xbbb    SBRC
1111    111s    ssss    xbbb    SBRS






Disassembler code en tabel (10)

: (IN       .DEST-REG  .PORT  ." IN," ;
: (OUT      .PORT  .DEST-REG  ." OUT," ;

: (RJMP     .RJMP  ." RJMP,"  .ISTRING ;
: (RCALL    .RJMP  ." RCALL," .ISTRING ;
: (LDI      .SHORT-REG  .CONSTANT  ." LDI," ;

EXEC-TABLE AVR-MAIN
    ' ZERO ,    ' ONE ,     ' TWO ,     ' (CPI ,
    ' (SBCI ,   ' (SUBI ,   ' (ORI ,    ' (ANDI ,
    ' EIGHT ,   ' NINE ,    ' TEN ,     ' ELEVEN ,
    ' (RJMP ,   ' (RCALL ,  ' (LDI ,    ' FIFTEEN ,

: DIS-OPCODE    ( addr1 -- addr2 )
    $1FFF AND                           \ Wrap around adresses
    DUP U2/ .HEX SPACE                  \ Show memory address
    DUP CELL+  SWAP B@  TO OPCODE       \ Advance to next addr. & save opcode
    HEX? IF
        OPCODE .HEX SPACE               \ Show opcode in hex
    THEN
    OPCODE 12 RSHIFT  AVR-MAIN          \ Disassemble
    ;




Simulator code en tabel (11)

: 'IN       I/O-DATA SWAP $20 + REG@  SWAP REG!     ( opc -- )
            1TICK ;

: 'OUT      I/O-DATA REG@ SWAP $20 + REG!           ( opc -- )
            1TICK ;

: 'RJMP     RJUMP  2TICKS ;                         ( opc -- )

: 'RCALL    PC >STACK  PC >< >STACK  RJUMP          ( opc -- )
            2TICKS  1TICK ;

: 'LDI      CONST-DATA  REG!  1TICK ;               ( opc -- )

:NONAME     OVER 12 RSHIFT ;
SIM-TABLE ONE-OPCODE
    ' ZERO ,    ' ONE ,     ' TWO ,     ' 'CPI ,
    ' 'SBCI ,   ' 'SUBI ,   ' 'ORI ,    ' 'ANDI ,
    ' EIGHT ,   ' NINE ,    ' TEN ,     ' ELEVEN ,
    ' 'RJMP ,   ' 'RCALL ,  ' 'LDI ,    ' FIFTEEN ,




'Egel listing en AVR versie daarvan (12)

\ Looplicht met AT89C2051 op poort 1, codelengte: 128 bytes.

89C2051                                 \ Compileer voor AT89C2051
$90 SFR LEDS                            \ Poort 1 met 8 leds

: KNIPPER       ( -- )                  \ Visualiseer opstarten
    0 TO LEDS   250 MS                  \ Alle leds aan
    -1 TO LEDS  250 MS                  \ Alle leds uit
    ;

: LOOPLICHT     ( -- )                  \ Een looplicht
    SETUP                               \ Installeer Forth stacks
    KNIPPER
    BEGIN
        8 0 DO                          \ Doe lus acht maal
            1 I LSHIFT                  \ Maak bitpatroon
            INVERT TO LEDS              \ Keer om en stuur de leds aan
            100 MS                      \ Wacht even
        LOOP
    AGAIN                               \ Begin weer opnieuw
    ;  MAIN                             \ LOOPLICHT start op na een reset



\ Looplicht op poort B, afm: 152 bytes vooral langer door MS macro !!

90S2313                                 \ Compileer voor AT90S2313
INCLUDE TARGET.FRT                      \ Laad labels & vectoren voor 90S2313

DDRB    SFR DIRB                        \ Poort B richtings register
PORTB   SFR LEDS                        \ Poort B met 8 leds

: KNIPPER       ( -- )                  \ Visualiseer opstarten
    0 TO LEDS   250 MS                  \ Alle leds aan
    -1 TO LEDS  250 MS                  \ Alle leds uit
    ;

: LOOPLICHT     ( -- )
    SETUP                               \ Installeer Forth machine
    SET DIRB                            \ Poort B wordt gebruikt als uitgang
    KNIPPER
    BEGIN
        8 0 DO                          \ Doe lus acht maal
            1 I LSHIFT                  \ Maak bitpatroon
            INVERT TO LEDS              \ Keer om en stuur de leds aan
            100 MS                      \ Wacht even
        LOOP
    AGAIN                               \ Begin weer opnieuw
    ;  MAIN                             \ LOOPLICHT start op na een reset




Drie maal CREATE DOES> (13)

\ Proefjes met CREATE DOES> in ByteForth  ( 202 bytes TARGET geheugen )

INTERPRETER  

: VAR       RAM CREATE  1 ALLOT  ALIGN  DOES> ;
: VARS      RAM CREATE  ALLOT    ALIGN  DOES> ROT M+ ;
: CON       ROM CREATE  ,        ALIGN  DOES> ROM@ ;

TARGET

1 CON EEN       2 CON TWEE

VAR AAP         VAR NOOT        10 VARS MIES

: WIM   AAP @  EEN +  NOOT ! ;      ( 32 bytes )        ( 107 cycles )
: INA   0 MIES @  EEN +  1 MIES ! ; ( 40 bytes )        ( 171 cycles )

\ Test CREATE voor gevorderden  ( 116 bytes TARGET geheugen )

CONSTRUCT

: CON
    ROM  CREATE  C,  IMMEDIATE
    DOES>  C@  FLYER  >R
        r16 r> ldi,  pusha, ;

: VAR
    RAM  CREATE  HERE C,  1 ALLOT  IMMEDIATE
    DOES>  C@  FLYER  >R
        r16 r> ldi,  pusha, ;

: VARS
    RAM  CREATE  HERE C,  ALLOT  IMMEDIATE
    DOES>  C@  FLYER  >R
        popa,  r16 R@ addi,  r17 R> adci,  2push, ;

METHODS VAR
    : TO    C@      popa,  [y] r16 st, no-output ;
    : FROM  C@ >R   r16 R> [y] ld,  pusha, ;
END-METHODS

METHODS VARS
    : TO    C@ >R   popa,  r16 R> addi, zl yl mov, zl r16 add,
                    zh clr, zh yh adc, r16 x+ ld, z r16 st, no-output ;
    : FROM  C@ >R   popa, r16 R> addi, zl yl mov, zl r16 add,
                    zh clr, zh yh adc, r16 z ld, pusha, ;
END-METHODS

TARGET

1 CON EEN       2 CON TWEE

VAR AAP         VAR NOOT        10 VARS MIES

: WIM   FROM AAP EEN +  TO NOOT ;       ( 14 bytes )    ( 14 cycles )
: INA   0 MIES @ EEN +  1 MIES ! ;      ( 38 bytes )    ( 28 cycles )
: RENE  0 FROM MIES  EEN +  1 TO MIES ; ( 42 bytes )    ( 30 cycles )

\ Test via ingebouwde defining word  ( 84 bytes TARGET geheugen )

TARGET

1 CONSTANT EEN      2 CONSTANT TWEE

VARIABLE AAP        VARIABLE NOOT       10 VARIABLES MIES

: WIM   FROM AAP  EEN +  TO NOOT ;      ( 10 bytes )    ( 10 cycles )
: INA   0 MIES @  EEN +  1 MIES ! ;     ( 42 bytes )    ( 28 cycles )
: RENE  0 FROM MIES  EEN +  1 TO MIES ; ( 10 bytes )    ( 10 cycles )




MPE AVR code v.s. AVR ByteForth en IAR C-compiler (14)

    : TST   3 I/O PORTA C! ;                : TST   3 TO PORTA ;

Uitkomst MPE zonder optimalisator  v.s.  ByteForth zonder optimalisator 
    ( 20 bytes code excl. C! )              ( 10 bytes code )
    PUSHT,                                  R16 3 LDI,
    TOSL 3 LDI,                             -X R16 ST,
    TOSH 0 LDI,                             R16 X+ LD,
    PUSHT,                                  PORTA R16 OUT,
    TOSL PORTA LDI,                         RET,
    TOSH 0 LDI,
    ' C! CALL,
    RET,

Uitkomst MPE met optimalisator      v.s.  ByteForth met optimalisator 
    ( 8 bytes )                             ( 6 bytes )
    R16 3 LDI,                              R16 3 LDI,
    PORTA R16 STS,                          PORTA R16 OUT,
    RET,                                    RET,


Voorbeeld 2, IAR C-compiler v.s. AVR ByteForth.

// Macros for setting/clring IO bits in the IAR C-compiler
// a=[sfr name] , b=[bit number]

#define set_sfrbit(a,b) ( (a) |= (1<<(b)))
#define clr_sfrbit(a,b) ( (a) &= (~(1<<(b))) )
#define test_sfrbit(a,b) ( (a) & (1<<(b)) )

#define DIVVALVE_PORT       PORTB
#define DIVVALVE_FOR        6       // Port B.6

void DivValveOnForward(void)
{
    set_sfrbit(DIVVALVE_PORT, DIVVALVE_FOR);
}

This generates an sbi or cbi instruction.


In AVR ByteForth gaat het zo:

PORTB  6  BIT-SFR VALVE    \ PB.6 controls valve

: VALVE-ON      ( -- )
    SET VALVE
    ;
