Lab 1: 6502 Emulator Bitmap Display and Performance Optimization
Introduction
This blog post details my experiments and learnings from Lab 1 of the 6502 programming course. The lab focuses on filling a bitmapped display with colors using assembly language and optimizing the program's performance on the 6502 emulator. I also explored modifying the display to achieve various effects, calculated execution time, and analyzed mistakes made during this process to understand the intricacies of performance analysis.
Code Overview: Filling the Screen with Yellow
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 ; Color number (yellow)
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
bne loop ; Continue until done with all pages
How the Code Works
Setup: A pointer is stored in memory locations $40 and $41, pointing to the start of the bitmap memory ($0200).
Color Assignment: The lda #$07 instruction sets the yellow color.
Inner Loop: The loop iterates over all 256 bytes (pixels) in a page, storing the color value.
Page Handling: The high byte in $41 is incremented to move to the next page after processing one page.
Outer Loop: The outer loop processes 6 pages (each with 256 pixels) to fill the entire bitmap display.
Performance Analysis
To calculate how long it takes to execute the code:
Pixels per page: 256 (0–255, as the Y register is 8-bit).
Pages processed: 6.
Total pixels: 1536.
Instruction Counts
The table below shows the instruction counts and cycles:
Instruction
Cycles
Count
Total Cycles
lda #$00
2
1
2
sta $40
3
1
3
lda #$02
2
1
2
sta $41
3
1
3
lda #$07
2
1
2
ldy #$00
2
1
2
sta ($40),y
6
1536
9216
iny
2
1536
3072
bne loop
3
1530
4590
inc $41
5
6
30
ldx $41
2
6
12
cpx #$06
2
6
12
bne loop
3
5
15
Total Cycles: 16,961.
Clock Time: 1 MHz
Cycle Time: 1μs
Execution Time: 16.961 ms (at 1 MHz clock speed).
Experiments
Here are the experiments from modifications to the original code:
1. Adding tya Before sta ($40),y
tya ; Transfer Y register to the Accumulator
sta ($40),y ; Store the A value at the address (pointer) + Y
Effect: Creates a gradient where each pixel color corresponds to its Y index. The screen displays 256 colors.
2. Adding lsr After tya
tya ; Transfer Y register to the Accumulator
lsr ; Logical Shift Right (divide by 2)
sta ($40),y ; Store the A value at the address (pointer) + Y
Effect: Reduces the number of colors to 128, creating a blocky gradient as each pair of Y values maps to the same color.
3. Adding Multiple lsr Instructions
tya ; Transfer Y register to the Accumulator
lsr ; Logical Shift Right (divide by 2)
lsr ; Logical Shift Right (divide by 4)
sta ($40),y ; Store the A value at the address (pointer) + Y
Effect: Each lsr halves the number of colors:
1 lsr: 128 colors
2 lsr: 64 colors
3 lsr: 32 colors
4 lsr: 16 colors
5 lsr: 8 colors
The gradient becomes more segmented with larger blocks of repeated colors.
4. Replacing lsr with asl
tya ; Transfer Y register to the Accumulator
asl ; Arithmetic Shift Left (multiply by 2)
sta ($40),y ; Store the A value at the address (pointer) + Y
Effect: Colors repeat every 128 Y values due to overflow, creating a mirrored gradient effect.
5. Adding Multiple asl Instructions
tya ; Transfer Y register to the Accumulator
asl ; Arithmetic Shift Left (multiply by 2)
asl ; Arithmetic Shift Left (multiply by 4)
sta ($40),y ; Store the A value at the address (pointer) + Y
Effect: Colors repeat more frequently as the overflow occurs faster:
1 asl: Overflow every 128 values
2 asl: Overflow every 64 values
3 asl: Overflow every 32 values
6. Adding Multiple iny Instructions
iny ; Increment Y
iny ; Increment Y
sta ($40),y ; Store the A value at the address (pointer) + Y
Effect: Skips pixels:
1 iny: Fills all pixels.
2 iny: Fills every second pixel.
3 iny: Fills every third pixel.
The resulting bitmap has gaps depending on the number of iny instructions.
Reflections on Mistakes
While performing the lab, I initially miscalculated:
Loop Iterations: I assumed the inner loop processed fewer pixels than the actual 256 per page.
Branching Behavior: Misunderstood how bne interacts with loop counters.
Page Handling: Ignored the significance of inc $41 for page transitions.
Reflections on Assembly Language
Writing in assembly language revealed the level of detail required to control hardware directly. It was rewarding to see the results visually on the bitmap display, and optimizing the program was a challenging but enlightening experience.
Conclusion
Through this lab, I learned how to analyze, optimize, and experiment with assembly language on the 6502 emulator. From filling the display with colors to optimizing performance, it was an engaging and educational journey.