View unanswered posts | View active topics It is currently Wed Jul 17, 2019 11:19 pm



Reply to topic  [ 1 post ] 
 program-structure macros for PIC16 
Author Message

Joined: Tue Dec 11, 2012 8:03 am
Posts: 265
Location: California
I have an article on using macros to give program structures in 6502 assembly, with links to the assembly-language source code, and had been planning to do it with the PIC also. I finally have that done, with the MPASM source code here. It has enough in common with the 6502 stuff that I probably won't write a separate article for it though. As we were discussing it here, BitWise recommended using MPASM's #v(x) feature to make it easier to synthesize the needed stack in the assembler. I might still convert to that, but I had already started with my other method that I had used for the 6502 on the C32 assembler, and since my plate is awfully full and what I have does work, I might just leave it as is.

The goal of these macros of course is to get better control of code by making it much more clear what you're doing, and getting rid of the mass of labels and jumps that commonly characterize assembly code. The macros let you keep full control of every speck of code laid down by the assembler, but you don't have to keep looking at the internal details. In most cases there is absolutely zero penalty in program memory taken or in execution speed. You get the performance of assembly with a lot of the benefits of higher-level languages. Code becomes quicker to develop, more bug-free, and easier to maintain, meaning that it's easier to come back later and figure out what you did when you decide to add a feature or change something.

For an example, take this short piece of code from my I²C sample code, actual code I used on a PIC12CE673 which had no SSP (even though the I²C serial EEPROM was onboard, with CLK and SDA on bits 6 & 7 of the GPIO) so the I²C had to be bit-banged:

Code:
RCV_I2C_BYTE:
        I2C_DATA_UP
        CLRF      EEPROM_DATA           ; Init EEPROM_DATA as 0.
        MOVLW     8
        MOVWF     LOOP_COUNT1
rib1:   I2C_DATA_UP
        I2C_CLK_UP
        CALL      RD_I2C_BIT
        I2C_CLK_DN
        DECFSZ    LOOP_COUNT1,F
        GOTO      rib1
        RETURN                          ; The ACK or NAK bit must be sent separately.
 ;----------------------------

(Even there, you can see the use of macros, as for example I2C_DATA_UP is more clear than BSF GPIO,6 but assembles exactly the same thing.) The loop is to gather the 8 bits of data to read for one byte. If we do a FOR...NEXT loop with the macros, we get:

Code:
RCV_I2C_BYTE:
        I2C_DATA_UP
        CLRF      EEPROM_DATA              ; Init EEPROM_DATA as 0.
        FOR LOOP_COUNT1, 8, DOWN_TO, 0
            I2C_DATA_UP
            I2C_CLK_UP
            CALL  RD_I2C_BIT
            I2C_CLK_DN
        NEXT      LOOP_COUNT1
        RETURN                             ; The ACK or NAK bit must be sent separately.
 ;----------------------------

Looking at the .hex file output, you would have no way of telling which source code it came from, because the assembled code is exactly the same for the two versions. In BASIC you would probably have the FOR...NEXT count up instead of down, but here it's more efficient to count down and end at zero since it allows branching on the Z flag without doing another comparison first. This way it just assembles the DECFSZ LOOP_COUNT1,F and then the GOTO like the more-manual version above.

Here's an example of using an "IF...END_IF" (and as you can see, it's also in part of a larger CASE statement). This is part of a project I'm working on.

Code:
           CASE_OF  4                         ; We were waiting for the low address byte to be shifted out to the flash memory.
               RAM_BANK  1                    ; Is that finished yet?  (Check buffer-full bit in SSP-status register.)
               IF_BIT  SSPSTAT, BF, IS_SET    ; If so,
                   RAM_BANK  0
                   CLRF  SSPBUF               ; send out a dummy byte in order to get the first data byte to read,
                   INCF  FLASH_RD_STATE,F     ; then increment the state.
               END_IF
           END_OF

In this case, the serial-port shifting for the given hardware takes time, and there's too much to do to twiddle our thumbs, so I have kind of a multitasking system where every time a task is called up, it looks to see if there's anything it can or should do at the moment, and if not, lets the computer move on to do other necessary things while it's waiting. (Don't worry about it being left in RAM bank 1 if the buffer-full bit is not set. There's a RAM_BANK 0 instruction right after the END_CASE.)

As you get a lot of decision-making, branching, looping, and exceptions to unevetful straight-line code, the macros become more and more valuable. It's nice going a hundred lines or more without a single label, and being able to more easily see the structure and the conditions under which the program carries out various operations. See the article for more info.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources


Sat Feb 02, 2013 10:50 am
Profile WWW
Display posts from previous:  Sort by  
Reply to topic   [ 1 post ] 

Who is online

Users browsing this forum: No registered users and 1 guest


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 post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software