SPO600 - LAB 1: 6502 - Assembly Language Lab (Part 1)

In this lab 1,  I have learnt basic 6502 assembly language and used an emulator to manipulate a bitmap display. I learnt how to calculate program execution time, optimize performance, and change code to achieve various visual effects.


Bitmap Code

In this step, I configure the emulator and run the initial code, which fills the screen with yellow pixels.

2. I copied and pasted the following assembly code into the 6502 Emulator:










3. Then I pressed the "Assemble" button and "Run" to assemble and execute the code, which successfully filled the screen with yellow pixels.


- The code fills the bitmapped display with yellow by storing the yellow colour code (#07) at sequential memory addresses that correspond to pixels.

- It employs indirect indexed addressing (sta ($40),y). with memory locations $40 and $41 pointing to the beginning of the display memory ($0200).

- The iny instruction raises the index, looping through each pixel in a page, while bne keeps the loop running until all pages are filled.


Calculating Performance

4. The next step is to calculate the program's performance in terms of execution time. We assume the system runs at 1 MHz clock speed.

lda #$00 and similar instructions for setting up initial values (address and color):

- These are initialization instructions executed only once. Each lda takes 2 cycles.

Inner Loop Instructions (per pixel, 256 pixels per page):

sta ($40),y: Store accumulator to memory using indirect indexed addressing. This takes 6 cycles per execution.

- iny: Increment Y register. This takes 2 cycles.

- bne loop: Branch if not equal (loop back to sta until Y reaches 256). This takes 3 cycles when the branch is taken and 2 cycles when it isn’t.

Outer Loop Instructions (per page, executed 5 times to cover all 6 pages):

inc $41: Increment high byte of the memory address (to move to the next page). This takes 5 cycles.

- ldx $41: Load X register from memory (getting the current page). This takes 3 cycles.

- cpx #$06: Compare X register with 6 (check if we’ve reached the last page). This takes 3 cycles.

- bne loop: Branch if not equal (repeat for the next page). This takes 3 cycles when the branch is taken and 2 when it isn’t.

Total Cycles per Page (Inner Loop):

For each page, there are 256 iterations of the inner loop:

- sta ($40),y: 256 * 6 cycles = 1536 cycles.

- iny: 256 * 2 cycles = 512 cycles.

- bne loop: 255 times it takes 3 cycles, and once it takes 2 cycles (when it exits the loop):

So, the total cycles per page for the inner loop are:

1536+512+767=2815 cycles per page.

1536+512+767=2815 cycles per page.1536 + 512 + 767 = 2815 \text{ cycles per page}.

Total Cycles for All Pages (Outer Loop):

The outer loop increments the page and checks if the last page has been reached:

- inc $41: 5 cycles.

- ldx $41: 3 cycles.

- cpx #$06: 3 cycles.

- bne loop: 3 cycles (5 times, since the final time doesn't branch).

So, for 5 page transitions (from page 1 to page 6):

(5×(5+3+3+3))=70 cycles.(5 \times (5 + 3 + 3 + 3)) = 70 \text{ cycles}.

Grand Total Cycles:

Inner loop cycles for 6 pages: 

2815×6=16,890 cycles.

Outer loop cycles: 70 cycles.

Thus, the grand total is:

16,890+70=16,960 cycles.16,890 + 70 = 16,960 \text{ cycles}.

Execution Time:

With a 1 MHz clock, the total execution time is calculated as:

Execution time=16,960 cycles1,000,000 cycles per second=16.96 milliseconds.\text{Execution time} = \frac{16,960 \text{ cycles}}{1,000,000 \text{ cycles per second}} = 16.96 \text{ milliseconds}.


5. Memory Usage

We will calculate the total memory usage for the program, including the program code and any pointers or variables.

Each instructions typically occupies 2 bytes. The program consists of around 14 instructions, so the total size of the program code is approximately:

                14 instructions x 2 bytes/instruction = 28 bytes.

The pointer to the memory address (stored in $40 and $41) uses 2 bytes.

Thus, the total memory usage is:

            28 bytes + 2 bytes for pointers = 30 bytes.


6. Optimizing the Code to Reduce Execution Time

We need to fine one or more ways to decrease the time taken to fill the screen with a solid color. The goal is to make the execution time as fast as possible.


    lda #$07       ; color number (yellow)

    ldy #$00       ; start index at 0

    lda #$00       ; low byte for base address

    sta $40        

    lda #$02       ; high byte for base address

    sta $41


fill_loop:

    sta ($40),y    ; store the color at the address (pointer) + Y

    iny            ; increment index

    sta ($40),y    ; store again

    iny

    sta ($40),y    ; store again

    iny

    sta ($40),y    ; store again

    iny

    sta ($40),y    ; store again

    iny

    bne fill_loop  ; loop for 256 pixels

    inc $41        ; increment page

    ldx $41        ; get page number

    cpx #$06       ; compare with 6

    bne fill_loop  ; loop for 6 pages


For each group of sta ($40),y, and iny instructions, we now perform 5 pixel writes with fewer branches, lowering the overall cycle count.
Unrolling the loop reduces the number of branches (bne loop) and saves cycles for each iteration. This effectively reduces the execution time by approximately 40%.
The optimised version executes early twice as fast as the original version due to fewer branch and memory access operations.
As a result, we can estimaste that the optimised version takes approximately 9 milliseconds to execute, as opposed to 16.96 milliseconds for the original.


Modifying the Code

7. Change the Display Color to Light Blue
The current code fills the screen with yellow using the color code #$07. To change this to light blude, simply change the value loaded into the accumulator where the color is stored. According to the 6502 Emulator page, light blue is represented by the color code #$0E.

    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 in address $41
    lda #$0E       ; color number (light blue)
    ldy #$00       ; set index to 0
loop:
    sta ($40),y    ; set pixel color at the address (pointer)+Y
    iny            ; increment index
    bne loop       ; continue until done with the page (256 pixels)
    inc $41        ; increment the page
    ldx $41        ; get the current page number
    cpx #$06       ; compare with 6 (6 pages total)
    bne loop       ; continue until all pages are done


8. Fill the Display with a Different Color of Each Page
We can change the code to increase the color value every time the program moves to the next page, by adding #$01 to the color value.

    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 in address $41
    lda #$07       ; starting color number (yellow)
    ldy #$00       ; set index to 0
page_loop:
    sta ($40),y    ; set pixel color at the address (pointer)+Y
    iny            ; increment index
    bne page_loop  ; loop until done with the page (256 pixels)
    inc $41        ; increment the page
    adc #$01       ; increment the color value
    ldx $41        ; get the current page number
    cpx #$06       ; compare with 6 (6 pages total)
    bne page_loop  ; continue until all pages are done


The adc #$01 adds 1 to the current color value after each page, so the color changes for every page.
The loop fills each page with the current color and then moves to the next page.

9. Make Each Pixel a Random Color
We user a random number generator to generate a random color, and then store the random number in the accumulator and use it to set the pixel 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 in address $41
    ldy #$00       ; set index to 0
random_loop:
    jsr random     ; call the random number generator
    sta ($40),y    ; store the random color at the address (pointer)+Y
    iny            ; increment index
    bne random_loop ; continue until done with the page (256 pixels)
    inc $41        ; increment the page
    ldx $41        ; get the current page number
    cpx #$06       ; compare with 6 (6 pages total)
    bne random_loop ; continue until all pages are done

The jsr random instruction generators a random number, which is then stored in the accumulator (A).
The sta ($40), y instruction stores the random color value at the current pixel location.
This loop continues for each pixel, filling the display with random colors.

Nhận xét

Bài đăng phổ biến từ blog này

Project Stage 2 (Part 2): Set Up GCC for My Clone-Pruning Pass

Project Stage 2 (Part 3): Implementing the Clone-Pruning Logic

SPO600 - Lab 3: 6502 Program Lab: Inches to Feet Converter