This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Inline Assembly & Interrupt Functions

Hello,
1) I want to place assembly code in my C code. The problem with using SRC is that I would have to rename the file MyAsm.SRC to MyAsm.A51 and then (remove C code from project) include A51 code in the project... before finally recompiling the whole project. Is there any way to just add assembly code without using SRC?
What about the '__asm' keyword? Where do I get more info on this?

2) The Cx51 User Manual (Pg124) states that the Interrupt function will save SFR, ACC, B, DPL, DPH etc 'when required' to stack (and later pop it). How do I disable this feature so I can manually do the PUSHing and POPing? If this is not possible then is it possible to instruct Keil to 'save all' registers regardless of need?

Regards,
KC

Parents
  • Hi Ken,

    that SRC thing is just a help for you to build the structure of a function. You just do it once, just typing in the function with its parameters and return value, use the parameters in the function in a simple (dummy) way, then you get assembly code, that declares the segments etc. and shows you where you will find your parameters. This is done once. You "steal" that assembly code mand do all the programming in assembler, never use the SRC pragma again.

    For example, if you want to write an assembly module that handles an LCD display, you first set up a "Prototyping C-source" lcd_prot.c that looks like this:

    #pragma SRC
    
    bit lcd_busy( void ) {
      return 1;
    }
    
    void lcd_out( unsigned char out_byte, unsigned char ram ) {
      if (ram) {
        out_byte++;
      }
    }
    
    void lcd_outchar( unsigned char out_byte ) {
      out_byte++;
    }
    
    void lcd_outinstr( unsigned char out_byte ) {
      out_byte++;
    } 
     
    void lcd_clear( void ) {
      unsigned char byte;
      
      byte++;
    }
    
    void lcd_init( void ) {
      unsigned char byte;
      
      byte++;
    }
    

    This doesn't do anthing reasonable, but when you compile it, you will get a file *.src that looks like this:
    ; c:\c51\proj\Test\lcd.SRC generated from: c:\c51\proj\Test\lcd.c
    
    
    NAME	LCD
    
    ?PR?lcd_busy?LCD     SEGMENT CODE 
    ?PR?_lcd_out?LCD     SEGMENT CODE 
    ?PR?_lcd_outchar?LCD SEGMENT CODE 
    ?PR?_lcd_outinstr?LCD                    SEGMENT CODE 
    ?PR?lcd_clear?LCD    SEGMENT CODE 
    ?XD?lcd_clear?LCD    SEGMENT XDATA OVERLAYABLE 
    ?PR?lcd_init?LCD     SEGMENT CODE 
    ?XD?lcd_init?LCD     SEGMENT XDATA OVERLAYABLE 
    ?PR?_lcd_gotoxy?LCD  SEGMENT CODE 
    ?PR?lcd_clreol?LCD   SEGMENT CODE 
    ?XD?lcd_clreol?LCD   SEGMENT XDATA OVERLAYABLE 
    	PUBLIC	lcd_clreol
    	PUBLIC	_lcd_gotoxy
    	PUBLIC	lcd_init
    	PUBLIC	lcd_clear
    	PUBLIC	_lcd_outinstr
    	PUBLIC	_lcd_outchar
    	PUBLIC	_lcd_out
    	PUBLIC	lcd_busy
    
    	RSEG  ?XD?lcd_clreol?LCD
           byte?545:   DS   1
    ; #pragma SRC
    ; #pragma LARGE
    ; 
    ; bit lcd_busy( void ) {
    
    	RSEG  ?PR?lcd_busy?LCD
    lcd_busy:
    			; SOURCE LINE # 4
    ;   return 1;
    			; SOURCE LINE # 5
    	SETB 	C
    ; }
    			; SOURCE LINE # 6
    ?C0001:
    	RET  	
    ; END OF lcd_busy
    [...]
    

    This lets you recognize the returnvalue of lcd_busy easily... it is contained in the Carry-Bit. Just copy the code and fill the structure with something reasonable written in assembler.

Reply
  • Hi Ken,

    that SRC thing is just a help for you to build the structure of a function. You just do it once, just typing in the function with its parameters and return value, use the parameters in the function in a simple (dummy) way, then you get assembly code, that declares the segments etc. and shows you where you will find your parameters. This is done once. You "steal" that assembly code mand do all the programming in assembler, never use the SRC pragma again.

    For example, if you want to write an assembly module that handles an LCD display, you first set up a "Prototyping C-source" lcd_prot.c that looks like this:

    #pragma SRC
    
    bit lcd_busy( void ) {
      return 1;
    }
    
    void lcd_out( unsigned char out_byte, unsigned char ram ) {
      if (ram) {
        out_byte++;
      }
    }
    
    void lcd_outchar( unsigned char out_byte ) {
      out_byte++;
    }
    
    void lcd_outinstr( unsigned char out_byte ) {
      out_byte++;
    } 
     
    void lcd_clear( void ) {
      unsigned char byte;
      
      byte++;
    }
    
    void lcd_init( void ) {
      unsigned char byte;
      
      byte++;
    }
    

    This doesn't do anthing reasonable, but when you compile it, you will get a file *.src that looks like this:
    ; c:\c51\proj\Test\lcd.SRC generated from: c:\c51\proj\Test\lcd.c
    
    
    NAME	LCD
    
    ?PR?lcd_busy?LCD     SEGMENT CODE 
    ?PR?_lcd_out?LCD     SEGMENT CODE 
    ?PR?_lcd_outchar?LCD SEGMENT CODE 
    ?PR?_lcd_outinstr?LCD                    SEGMENT CODE 
    ?PR?lcd_clear?LCD    SEGMENT CODE 
    ?XD?lcd_clear?LCD    SEGMENT XDATA OVERLAYABLE 
    ?PR?lcd_init?LCD     SEGMENT CODE 
    ?XD?lcd_init?LCD     SEGMENT XDATA OVERLAYABLE 
    ?PR?_lcd_gotoxy?LCD  SEGMENT CODE 
    ?PR?lcd_clreol?LCD   SEGMENT CODE 
    ?XD?lcd_clreol?LCD   SEGMENT XDATA OVERLAYABLE 
    	PUBLIC	lcd_clreol
    	PUBLIC	_lcd_gotoxy
    	PUBLIC	lcd_init
    	PUBLIC	lcd_clear
    	PUBLIC	_lcd_outinstr
    	PUBLIC	_lcd_outchar
    	PUBLIC	_lcd_out
    	PUBLIC	lcd_busy
    
    	RSEG  ?XD?lcd_clreol?LCD
           byte?545:   DS   1
    ; #pragma SRC
    ; #pragma LARGE
    ; 
    ; bit lcd_busy( void ) {
    
    	RSEG  ?PR?lcd_busy?LCD
    lcd_busy:
    			; SOURCE LINE # 4
    ;   return 1;
    			; SOURCE LINE # 5
    	SETB 	C
    ; }
    			; SOURCE LINE # 6
    ?C0001:
    	RET  	
    ; END OF lcd_busy
    [...]
    

    This lets you recognize the returnvalue of lcd_busy easily... it is contained in the Carry-Bit. Just copy the code and fill the structure with something reasonable written in assembler.

Children
  • "that SRC thing is just a help for you to build the structure of a function."

    Well, that's certainly a very good way to write C51-compatible assembler functions, but it is by no means the sole purpose of this facility!

    Having said that, I still doubt the wisdom of what Ken is suggesting!

  • Hello,
    Thank You All.
    The problem is that I need to do some manual saving of registers to stack. However with interrupts.. I dont know in advance which register are being saved. Is there any way to disable Keil from doing this register saving?
    Will it make any difference if I write the ISR totally in Assembly?
    Regards,
    KC

  • Will it make any difference if I write the ISR totally in Assembly?
    if you do that EVERYTHING including register saves (do not forget the PSW) is up to you, nothing is automatic. Usually a bank swotch ("using") is a better solution if you use several registers.

    Erik

  • "The problem is that I need to do some manual saving of registers to stack."

    But why???
    C51 guarantees that it will preserve registers through an interrupt function.

    As I said before, if you really do need so do this, then you should do it entirely in assembler - as Erik said, that guarantees that you are totally in control of everything that goes on (and, therefore, to blame for anything that goes wrong!!)