flat assembler
Message board for the users of flat assembler.

Index > Non-x86 architectures > [x51] Some usefull macros for 8051

Author
Thread Post new topic Reply to topic
shoorick



Joined: 25 Feb 2005
Posts: 1614
Location: Ukraine
shoorick 27 Jun 2018, 10:03
Code:
;-----------------------------------------------------------------------
include "8051.inc"
;-----------------------------------------------------------------------
macro ORGX? addr,filler=0 ; org with padding (aka align)
  if ~ (addr = $) 
    db (addr - $) dup (filler)
  end if
end macro  
;-----------------------------------------------------------------------
macro SELECT_BANK? n ; select working register bank
   if n>3
     err "Wrong bank number!"
   end if
   if n and 1
     setb RS0
   else
     clr  RS0
   end if
   if n and 2
     setb RS1
   else
     clr  RS1
   end if
end macro
;-----------------------------------------------------------------------
LAST_FLAG_ADDR=1Fh
;-----------------------------------------------------------------------
macro FLAG? new_flag        ; define a flag in the bit-addressable area
    if ~ defined LAST_FLAG
      restore LAST_FLAG
      LAST_FLAG=0
    else
      LAST_FLAG=LAST_FLAG+1
    end if
    if LAST_FLAG > 7Fh
      err "Too many flags!"
    end if
    
    new_flag := LAST_FLAG
    
    LAST_FLAG_ADDR=LAST_FLAG shr 3 + 20h
    
end macro
;-----------------------------------------------------------------------
macro DATA? new_data,bytes=1 ; define byte(s) from the top
    if ~ defined MEM_TOP     ; of the scratchpad 
      restore MEM_TOP        ; by default is not including
      MEM_TOP=80h            ; range above 7Fh (i8052)
    end if
    if ~ defined MEM_BOTTOM
      restore MEM_BOTTOM
      MEM_BOTTOM=30h ; 20h..2Fh - bitfield area (flags)
    end if
    MEM_TOP=MEM_TOP-bytes
    if MEM_TOP<MEM_BOTTOM
      err "DATA declaration address is below MEM_BOTTOM"
    end if
    
    new_data := MEM_TOP
    
end macro
;-----------------------------------------------------------------------
    STACK=2Fh
    STACK_SIZE=16
;-----------------------------------------------------------------------
    DATA_BOTTOM=STACK+STACK_SIZE+1  
;-----------------------------------------------------------------------
    

These macros make simple framework to manage internal RAM of x51 MCU.

Simply, you may do that:
- allocate byte in scratchpad:
DATA MYBYTE
mov MYBYTE,#15

- allocate some bytes:
DATA MYBYTES,4
mov R0,#MYBYTES

- define a bit flag:
FLAG BLINK
jnb BLINK,.m1


The idea is in defining RAM areas: The stack is placed above flags area (bit-addressable locations), free memory is limited with ram top (7Fh) and ram bottom (top of the stack).
Implicit allocation gives some insurance of not overlapping of data with checking for crossing boundaries, if there is an insufficiency of resources the warning will be flagged - then some rearrangement can be performed.

Also there is a macro for easy selection of the bank of registers:
SELECT_BANK 1
keep in mind that this selection does not preserve previous bank settings, so, PUSH PSW/POP PSW in procedure must be present to restore bank on return.

also, there is an orgx - a variant of org with aligning, usefull for binary output

_________________
UNICODE forever!


Last edited by shoorick on 02 Jul 2018, 10:15; edited 1 time in total
Post 27 Jun 2018, 10:03
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 30 Jun 2018, 13:16
These are some interesting subjects for a macro design. Just as an exercise I made a different variant of the DATA macro that allows to defined data in virtual blocks and preserves the order of defined variables in memory, while still allocating them off the top of the 30h-80h area. The new feature of VIRTUAL block continuation (implemented both in fasmg and fasm 1) is perfect for this:
Code:
MEM_BOTTOM := 30h
MEM_TOP := 80h

assert MEM_TOP-MEM_BOTTOM >= SCRATCHPAD_SIZE

virtual at 80h-SCRATCHPAD_SIZE
  ScratchPad::
end virtual

postpone
  virtual ScratchPad
    SCRATCHPAD_SIZE := $-$$
  end virtual
end postpone

macro DATA?
  virtual ScratchPad
end macro

macro END?.DATA?
  end virtual
end macro    
The syntax for this variant looks like this:
Code:
DATA
  MYBYTE DB ?
END DATA    
But you could also make a variant that would accept either syntax:
Code:
macro DATA? name,size:1
  virtual ScratchPad
  match any, name
    name rb size
    end virtual
  end match
end macro

macro END?.DATA?
  end virtual
end macro    


Well, you could also use "VIRTUAL ScratchPad" + "END VIRTUAL" directly, I think it could also look good.
Post 30 Jun 2018, 13:16
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 30 Jun 2018, 13:21
Also, for your FLAG macro I could suggest a small syntax wrapper:
Code:
macro FLAGS?
  macro ?! line&
    match =END? =FLAGS?, line
      purge ?
    else
      FLAG line
    end match
  end macro
end macro    
And then the flag definition could alternatively look like this:
Code:
FLAGS
  MYFLAG
  MYOTHERFLAG
END FLAGS    
What do you think of it?
Post 30 Jun 2018, 13:21
View user's profile Send private message Visit poster's website Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1614
Location: Ukraine
shoorick 30 Jun 2018, 17:19
Thanks!

I like this kind of data definition:
Code:
DATA
  MYBYTE DB ?
END DATA    
, it can be used alternatively (both variants can not be used simultaneusly I think).

++++++++++++++++++++++++++++++++++++++++++++++++
With your DATA definition there will be no necessity in such tricks like I made to adapt one known library to use with fasmg:
Code:
DATA Math_32_Data,Math_32_Data.size
virtual at Math_32_Data
Load_16_byte:   dw 0
Load_32_byte:   dd 0
Mul_16_byte:    dw 0
Div_16_byte:    dw 0
Add_16_byte:    dw 0
Sub_16_byte:    dw 0
Add_32_byte:    dd 0
Sub_32_byte:    dd 0
OP_0:           db 0
OP_1:           db 0
OP_2:           db 0
OP_3:           db 0
TMP_0:          db 0
TMP_1:          db 0
TMP_2:          db 0
TMP_3:          db 0
Math_32_Data.size=$-$$
end virtual    


I think I'll modify all my projects to use new DATA variant (thanks to gods there are only few of them yet Rolling Eyes )
++++++++++++++++++++++++++++++++++++++++++++++++

What about flags - I would prefer separate flag declaration like I did, but maybe somebody else may like your variant.

_________________
UNICODE forever!
Post 30 Jun 2018, 17:19
View user's profile Send private message Visit poster's website Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1614
Location: Ukraine
shoorick 06 Jul 2018, 20:00
well, I made this new version of data management:
Code:
;-----------------------------------------------------------------------
include "8051.inc"
;-----------------------------------------------------------------------
macro ORGX? addr,filler=0 ; org with padding (aka align)
  if ~ (addr = $) 
    db (addr - $) dup (filler)
  end if
end macro  
;-----------------------------------------------------------------------
macro SELECT_BANK? n ; select working register bank
   if n>3
     err "Wrong bank number!"
   end if
   if n and 1
     setb RS0
   else
     clr  RS0
   end if
   if n and 2
     setb RS1
   else
     clr  RS1
   end if
end macro
;-----------------------------------------------------------------------
LAST_FLAG_ADDR=1Fh
;-----------------------------------------------------------------------
macro FLAG? new_flag        ; define a flag in the bit-addressable area
    if ~ defined LAST_FLAG
      restore LAST_FLAG
      LAST_FLAG=0
    else
      LAST_FLAG=LAST_FLAG+1
    end if
    if LAST_FLAG > 7Fh
      err "Too many flags!"
    end if
    
    new_flag := LAST_FLAG
    
    LAST_FLAG_ADDR=LAST_FLAG shr 3 + 20h
    
end macro
;-----------------------------------------------------------------------
STACK_SIZE=16

if ~ defined MEM_TOP     ; of the scratchpad 
  restore MEM_TOP        ; by default is not including
  MEM_TOP=80h            ; range above 7Fh (i8052)
end if                   ; can be overrided in the start of main prog

assert MEM_TOP-DATA_BOTTOM >= SCRATCHPAD_SIZE

virtual at MEM_TOP-SCRATCHPAD_SIZE
  ScratchPad::
end virtual

postpone
  STACK=LAST_FLAG_ADDR
  DATA_BOTTOM=STACK+STACK_SIZE+1  
  virtual ScratchPad
    SCRATCHPAD_SIZE := $-$$
  end virtual
end postpone

macro DATA?
  virtual ScratchPad
end macro

macro END?.DATA?
  end virtual
end macro
;-----------------------------------------------------------------------    

The main difference in logic is calculating of DATA_BOTTOM: DATA_BOTTOM is similar to STACK with STACK_SIZE offset, but STACK now is LAST_FLAG_ADDR, so, bit-addresable bytes unused for flags are now wasted, stack is shifted in their area and area for data is increasing.
It looks as it works, but there is a problem appeared: it does not work with listing macro :S Thus, I've got some proofs through monitor program (see picture).


Description:
Filesize: 12 KB
Viewed: 17916 Time(s)

2018-07-06-225759_1280x1024_scrot.png



_________________
UNICODE forever!
Post 06 Jul 2018, 20:00
View user's profile Send private message Visit poster's website Reply with quote
shoorick



Joined: 25 Feb 2005
Posts: 1614
Location: Ukraine
shoorick 08 Apr 2019, 05:03
Simple SMBus communication
Code:
;-----------------------------------------------------------------------
; Clock stretching by slave is not implemented!
; Delay set to provide ~50kHz smbus clock at 24MHz main clock.
; If the main clock is less, smb_delay must be decreased to not
; go below 10kHz smbus clock! 
;-----------------------------------------------------------------------
DATA SMB_ADDR ; SMBUS DEVICE ADDR shifted 1 bit left
;-----------------------------------------------------------------------
SDA equ P3.3
SCL equ P3.2
;-----------------------------------------------------------------------
smb_read_byte: ; A - REG
    push IE
    clr  EA
    push ACC
    call smb_start
    mov  A,SMB_ADDR ; W
    call smb_put
    call smb_get_ack
    pop  ACC 
    call smb_put
    call smb_get_ack
    call smb_start
    mov  A,SMB_ADDR
    inc  A          ; R
    call smb_put
    call smb_get_ack
    call smb_get
    call smb_get_ack ; =master nack
    call smb_stop
    pop  IE
    ret
;-----------------------------------------------------------------------
smb_write_byte: ; A - REG, B - DATA
    push IE
    clr  EA
    push ACC
    call smb_start
    mov  A,SMB_ADDR ; W
    call smb_put
    call smb_get_ack
    pop  ACC 
    call smb_put
    call smb_get_ack
    xch  A,B
    call smb_put
    call smb_get_ack
    call smb_get
    call smb_get_ack 
    call smb_stop
    pop  IE
    ret
;-----------------------------------------------------------------------
smb_start:
    setb SCL
    call smb_delay
    setb SDA
    call smb_delay
    clr  SDA
    call smb_delay
    clr  SCL
    call smb_delay
    ret
;-----------------------------------------------------------------------
smb_stop:
    clr  SDA
    setb SCL
    call smb_delay
    clr  SCL
    call smb_delay
    setb SCL
    setb SDA
    call smb_delay
    ret
;-----------------------------------------------------------------------
smb_get_ack:
    setb SDA
    setb SCL
    call smb_delay
    mov  C,SDA
    clr  SCL
    call smb_delay
    ret
;-----------------------------------------------------------------------
smb_get:
    push B
    mov  B,#8
.loop:
    setb SCL
    mov  C,SDA
    addc A,ACC
    call smb_delay
    clr  SCL
    call smb_delay
    djnz B,.loop
    pop  B
    ret    
;-----------------------------------------------------------------------
smb_put:
    push B
    mov  B,#8
.loop:
    add  A,ACC
    mov  SDA,C
    setb SCL
    call smb_delay
    clr  SCL
    call smb_delay
    djnz B,.loop
    pop  B
    ret    
;-----------------------------------------------------------------------
smb_delay:
    call   .u5  
.u5:  
    nop    ; 5 us @ 24MHz
    nop    ; 
    nop    ; 4 us
    nop    ; 
    nop    ; 3 us
    nop    ; 
    ret    ; 2 us (1 us + 1 us call)
;-----------------------------------------------------------------------    

To make it perfect there should be checking bus for deadlock or no acknolegement by slave, but this code can be easely extended.
If clock is 12MHz, smb_delay can be like this:
Code:
smb_delay:
    nop    
    nop    
    nop    
    nop   
    nop   
    nop   
    ret    


Tested with used MAX6657 Smile

Reading MAX6657 manufacturer ID:
Code:
MAX6657_ADDR := 10011000b ; shifted left 1 bit
    mov  SMB_ADDR,#MAX6657_ADDR ; can be set once
    mov  A,#0xFE
    call smb_read_byte    


Setting overtemp level at 60°C:
Code:
    mov  A,#0x20
    mov  B,#60
    call smb_write_byte
    

_________________
UNICODE forever!
Post 08 Apr 2019, 05:03
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.