Lab 2 - SPO600

Introduction

Welcome to the second installment of our journey into the fascinating realm of 6502 assembly language programming. In this lab, we will delve into the intricacies of this low-level language, starting with an examination of the performance and optimization of a code snippet that fills the emulator's bitmapped display with a vibrant yellow hue.

Our primary focus will be on a snippet of code that accomplishes the task of painting the screen yellow. However, we won't stop at mere execution; we'll dissect the code, understand its inner workings, and experiment with ways to make it more efficient.

We'll calculate execution times based on a clock speed of 1 MHz and determine the memory usage for the program code and associated pointers or variables. Our ultimate goal is to devise the fastest version of this program, aiming for more than double the speed of the original.

But that's not all. We'll also modify the code to fill the display with different colors, challenge ourselves with optional experiments, and even tackle some advanced challenges. If you're ready to embark on this coding adventure, grab your keyboard, and let's dive into the world of 6502 assembly language.

For this Lab I am going to use the emulator from this website : https://skilldrick.github.io/easy6502/
As the emulator given by our professor was not working(may be some server error)

Without further ado, let's begin our exploration of assembly language programming!


Bitmap Code

The below code fills the bitmapped display with yellow color:

    LDA #$00    ; set a pointer in memory location $40 to point to $0200
    STA $40        ; ... low byte ($00) goes in address $40
    LDA #$02    
    STA $41        ; ... high byte ($02) goes into address $41

    LDA #$07    ; colour number

    LDY #$00    ; set index to 0

loop:    STA ($40),y    ; set pixel colour at the address (pointer)+Y

    INY        ; increment index
    BNE loop    ; continue until done the page (256 pixels)

    INC $41        ; increment the page
    LDX $41        ; get the current page number
    CPX #$06    ; compare with 6
    BNE loop    ; continue until done all pages

like this:

This code is pretty straightforward. We start by storing the value of the first pixel in memory addresses $40 and $41. Then, we iterate through each pixel on a page, setting its color. Once we finish one page, we move to the next, and we do this for a total of four pages. Memory locations $200 to $5FF map to the screen pixels, and we start from $0200 and keep incrementing until $05FF.

Let's calculate the performance of this code.


Calculating Performance

To calculate the performance of this code we can count the total number of cylcles and byte each instruction will take and then add them up to get total cycles and bytes.

So this is the cycle count and byte I have calculated for each instructions:

 

 

Bytes

Cycles

Cycle Count

Alt Cycles

Alt count

Total

 

 

 

 

 

 

 

 

 

lda #$00

2

2

1

 

 

2

 

sta $40       

2

3

1

 

 

3

 

lda #$02

2

2

1

 

 

2

 

sta $41

2

3

1

 

 

3

 

 

 

 

 

 

 

0

 

lda #$07 

2

2

1

 

 

2

 

 

 

 

 

 

 

0

 

ldy #$00 

2

2

1

 

 

2

 

 

 

 

 

 

 

0

loop: 

  sta ($40),y 

3

6

1024

 

 

6144

 

 

 

 

 

 

 

0

 

iny 

1

2

1024

 

 

2048

 

bne loop

2

3

1020

2

4

3068

 

 

 

 

 

 

 

0

 

inc $41

2

5

4

 

 

20

 

ldx $41

2

3

4

 

 

12

 

cpx #$06

2

2

4

 

 

8

 

bne loop

2

3

3

2

1

11

 

 

26

 

 

 

Total:

11325

cycles

CPU Speed: 

1

MHz

uS per clock

1

 

Time:

11325

uS

 

11.325

mS

 

0.011325

S

So, the total time it takes to execute this program is 0.011325 seconds.

Total program code size: 26 bytes

Memory locations $40 and $41 are used for pointers and variables, each taking up 1 byte.

Total for pointers and variables: 2 bytes

So, the total memory usage for your program (assuming it's stored in RAM) is:

Program code size + Pointers and Variables = 26 bytes + 2 bytes = 28 bytes


Modifying the Code

Lets Modify our code to print blue color

To do that we just need to change the color number from 07 to 06

    LDA #$00    ; set a pointer in memory location $40 to point to $0200
    STA $40        ; ... low byte ($00) goes in address $40
    LDA #$02    
    STA $41        ; ... high byte ($02) goes into address $41

    LDA #$06    ; colour number <-- here we change it to 06

    LDY #$00    ; set index to 0

loop:    STA ($40),y    ; set pixel colour at the address (pointer)+Y

    INY        ; increment index
    BNE loop    ; continue until done the page (256 pixels)

    INC $41        ; increment the page
    LDX $41        ; get the current page number
    CPX #$06    ; compare with 6
    BNE loop    ; continue until done all pages

Our output would we like this:

Lets modify our code to fill the display with a different colour on each page .

To achive that we can just change the value of color.
In my code I have achieved that by adding 01 value in the accumulate after one page color has printed

So, in the begining the value was #$06, after one loop it becomes #$07 then #$08 and then last #$09.

    LDA #$00    ; set a pointer in memory location $40 to point to $0200
    STA $40        ; ... low byte ($00) goes in address $40
    LDA #$02    
    STA $41        ; ... high byte ($02) goes into address $41

    LDA #$06    ; colour number

    LDY #$00    ; set index to 0

loop:    STA ($40),y    ; set pixel colour at the address (pointer)+Y

    INY        ; increment index
    BNE loop    ; continue until done the page (256 pixels)

    INC $41        ; increment the page
    LDX $41        ; get the current page number
     CLC         ; clear any carry 
       ADC #$01    ; add value 01 in accumulator
    CPX #$06    ; compare with 6

    BNE loop    ; continue until done all pages

Our output is going to look like this:

Lets modify our code to make it little faster.

To do that we have to lower the number of instructions we are executing one of the possible solution is loading the x register at the beginning and then just comparing the highest byte with the x register. lets see the code:

    LDA #$00    ; set a pointer in memory location $40 to point to $0200
    STA $40        ; ... low byte ($00) goes in address $40
    LDA #$02    
    STA $41        ; ... high byte ($02) goes into address $41

    LDA #$06    ; colour number
    LDX #$06    ; load x register with 06  
    LDY #$00    ; set index to 0

loop:    STA ($40),y    ; set pixel colour at the address (pointer)+Y

    INY        ; increment index
    BNE loop    ; continue until done the page (256 pixels)

    INC $41        ; increment the page

    CPX $41    ; compare X register with higher byte after increament the higher byte

    BNE loop    ; continue until done all pages

by doing this we have 3 less instructions but that is not enough. Think of some ways by which we can execute less and less instructions and achieve the same result.

Lets experiment with our code a bit:

Experiments

  1. If we add this instruction after the loop: label and before the sta ($40),y instruction: tya like this:
    LDA #$00    ; set a pointer in memory location $40 to point to $0200
    STA $40        ; ... low byte ($00) goes in address $40
    LDA #$02    
    STA $41        ; ... high byte ($02) goes into address $41

    LDA #$07    ; colour number  -- even if we remove this line same thing --

    LDY #$00    ; set index to 0

loop:
tya             ; transfer y to accumulator    <--- this is the new line added
STA ($40),y    ; set pixel colour at the address (pointer)+Y

    INY        ; increment index
    BNE loop    ; continue until done the page (256 pixels)

    INC $41        ; increment the page
    LDX $41        ; get the current page number
    CPX #$06    ; compare with 6
    BNE loop    ; continue until done all pages

our output is going to look like this:

We can observe from the above out that it is printing all the 16 colors in line consecutively at each pixel.

It is very clear from the code that with this instruction tyawe are transfering the value of y into the accumulator.

Moreover that instruction is inside the loop and after transfering the value from the loop it is increased by one and then again transfered into accumulator. So the loop started with 0 and will run all the way to f and our bitmapped dispaly is 32 pixel wide so it will repeat the colors. So, that's why we are able to see all the color lines.

💡
$1: White $2: Red $3: Cyan $4: Purple $5: Green $6: Blue $7: Yellow $8: Orange $9: Brown $a: Light red $b: Dark grey $c: Grey $d: Light green $e: Light blue $f: Light grey

Conclusion

Congratulations on completing the second installment of our journey into 6502 assembly language programming! In this lab, we have learned how to calculate the performance and memory usage of assembly code, modified the code to fill the screen with a different color, and explored optional experiments and advanced challenges to further enhance your skills.

Assembly language programming can be challenging but incredibly rewarding. The more you experiment and practice, the more proficient you'll become. Whether you're interested in retro game development, demoscene productions, or low-level systems programming, assembly language is a valuable skill to have in your toolkit.

Keep exploring, learning, and coding, and don't hesitate to reach out if you have any questions or need assistance on your assembly language journey. Happy coding!