Writing maintainable code - Falmouth-Games-Academy/comp310-wiki GitHub Wiki

Abstract

Maintainable code is important as software changes so frequently we need to be able to rewrite, update and change existing code 1(http://www.basilv.com/psd/blog/2006/the-importance-of-maintainable-software).

Introduction

Maintainable code should be easy to read, understand, change, change without breaking too much and if it does break it shouldn't be too hard to find to debug 2(https://software.ac.uk/resources/guides/developing-maintainable-software).

Assembly Code Maintainability

Assembly language consists mainly of symbols, numbers and random letters which of course make it impossible to understand by anyone who is not an expert in assembly or didn't write the code themselves 3(http://www.sourceformat.com/coding-standard-asm-assembly.htm#HEADING1-405).

Comments

As Assembly code is made of up of symbols, numbers and random letters it is especially important to add comments to your code when using assembly. "They are not just for other people to read - you read your own code more often than others do" 6(https://www.d.umn.edu/~gshute/asm/comments.xhtml). They are especially important for you as the programmer because it is difficult for anyone who is not an expert in Assembly to effectively read code, which can make debugging much more difficult to do without comments to remind you what the code is doing.

In assembly comments are done using semi-colon. For example:

TXA         ; Transfers the value currently stored in X to be stored in A 

Macros and Subroutines

When programming assembly code, there will be times when lines of code are being repeated. One of the key ways of dealing with this repeated code is through the use of macros and subroutines.

Subroutines

If the code you are running needs to have multiple calls that are the exact same you can use a subroutine which will have a performance penalty in terms of processing but can save large amounts of program memory in the process 4(http://wilsonminesco.com/StructureMacros/). Jump statements such as subroutine calls are bad for optimisation because they're another instruction to be processed. It is up to the developer to deem whether the drop in performance is worth making ones code more maintainable.

When including subroutines in your program, care should be taken to ensure that the subroutine will not be executed by the 'go to next line' nature of the assembly language. This can be easily achieved by placing the subroutine outside of the main body of code. For example after the non-maskable interrupt (NMI) RTI instruction.

An example of a subroutine written in assembly language. Note the colon following the subroutine's name. This tells the program that it can jump to this line

SubroutineName_DoSomething:
    ; Do something here
    RTS       ; Return back to the location from which it was called

Unless the subroutine has been fallen into following a previous line of code, it can be jumped to by using the JSR (Jump to Sub Routine) instruction.

    JSR SubroutineName_DoSomething    ; If the subroutine has an RTS instruction, then it 
                                      ; will return to this line upon executing the RTS

However, cleverly written code may require an internal jump to be truly optimum or fulfill a specific purpose, for instance a loop (to avoid an infinite loop a count should obviously be employed). Branch instructions are used to either repeat or jump out of a loop. Furthermore, these can be kept in a local scope by prefixing the subroutine declaration with a .. This can aid with readability, avoiding having to adhere to some complex naming convention to avoid accidently looping between an obscure LoopX: placed elsewhere in the program.

SubroutineName_DoSomethingTenTimes:
    LDX #10          ; Load a value of 10 into the X register
.LocalLoop:          ; Start of local subroutine
    ; Do something here
    SEC              ; Set the carry flag
    DEX              ; Decrement the value in the X register
    BNE .LocalLoop   ; If the value in the X register is not zero, branch
                     ; to the start of the local subroutine
    RTS              ; Return back to the location from which it was called

Macros

Macros are similar to subroutines however, a macro allows for the repeated code to have small changes made. Acting similarly to a function which takes in arguments. This can be useful for performing tasks that need to change based on a variable or if you need to perform the same action multiple time like when moving a sprite.

Macros are defined in assembly language in the following way.

MacrosName_DoSomething .macro
    ; Do something here
    .endm

But the real power of macros is the ability to pass in parameters. Up to nine parameters can be passed in by reference by comma seperating the values after the macro call and referred to within the macro by a \ symbol followed by the 1 based count position of that value within the arguments list.

For example

AddTogether .macro
    LDA \1     ; Load the first parameter into the A register
    CLC        ; Clear the carry flag
    ADC \2     ; Add the second parameter to the A register
    STA \3     ; Store the A register into the third parameter
    .endm

    AddTogether #firstValue, #secondValue, resultMemAddress

References