Hi Dev community,
This is my first time writing any blog post please bear with me, I am taking a course called software portability and optimisation. So lets start with the basics. What is Portability?
Most software is written in a high-level language which can be compiled into machine code for a specific computer architecture. In many cases, this code can be compiled or interpreted for execution on multiple computer architectures - this is called 'portable' code. Software portability refers to the ability of a software system to be easily transferred or adapted to different environments without requiring extensive modifications. In essence, it's about how easily software can be moved or reused across different platforms, operating systems, hardware architectures, or even programming languages.
Now you might ask me that we can still write code in high level programming language and make portable enough. But the actual reason of writing code in machine specific Assembly language lies below.
Performance
Atomic Operations
Direct access to hardware specific features like CPUID registers
So today in this post I am going to take you through my experience of writing my first Assembly language code and how I optimised it to reduce the execution time even though its for a few seconds because remember in Assembly less is more.
I worked on the 6502 processor a simple 8-bit processor that powered a number of early microcomputers (and video games).The 6502 (or a slight variation) was therefore used in many home and personal computers, such as the Apple II; the Commodore PET, Vic-20, and C64; the Atari 400 and 800; the BBC Micro; and games such as the Nintendo Entertainment System (NES), Atari 5200, and Atari 6200.
Before that you might want to take a look at the basic intructions like Registers , Addressing Modes and the emulator.
Bitmap Code
The following code fills the emulator's bitmapped display with the colour 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 ; 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
Calculating Performance
When you calculate the amout of time taken below are the results that you get, given that you do it right 😉
Dont worry below are the calculations 😃.
At this point the code takes 11.321 miliseconds to colour the whole display screen. Now my task was to optimize this code in such a manner that reduces the time to colour the whole display lets see how we can do it.
The Seceret Revealed. 🤫
If you notice the line number 7 where the loop starts and we set the pixel colour at the address
loop: sta ($40),y
We can use absolute values and instaed of setting the point first and then colouring it later we can do this simultaneously by changing the code as follows
lda #$07 ; colour number
ldy #$00 ; set index to 0
loop: sta $0200,y ; set pixel colour at page 2+y
sta $0300,y ; set pixel colour at page 3+y
sta $0400,y ; set pixel colour at page 4+y
sta $0500,y ; set pixel colour ar page 5+y
iny ; increment index
bne loop ; continue until done the page (256 pixels)
Here we are setting the pixel colour and adding y to that page at the same time which saves a lot of counts as compared to the previous code where we are running 2 loops.
The calculation will change as follows.
The program time reduced drastically to almost half of the time taken before. Now the program takes 6.403 miliseconds.
So this is the magic of optimization.
If you want to change the colour from yellow to light blue just change the color number to light blue colour number
lda #$e ; colour number
You can also change the code to fill the display with a different colour on each page.
ldy #$00 ; set index to 0
loop: lda #$e ; colour number
sta $0200,y ; set pixel colour at page 2+y
lda #$f ; colour number
sta $0300,y ; set pixel colour at page 3+y
lda #$3 ; colour number
sta $0400,y ; set pixel colour at page 4+y
lda #$a ; colour number
sta $0500,y ; set pixel colour ar page 5+y
iny ; increment index
bne loop ; continue until done the page (256 pixels)
Experiments
Since I am a computer Science student I cannot resist the urge to experiment wiht my code. I don't mind if I ruin it atleast I would learn from it.
- So, let's add
tya
after theloop:
and before thesta ($40),y
in the original Bitmap code. This will be the follwoing result 🫢
The reason behind such vibrant colours appearing is
- The instruction "tya" transfers the value of the index register Y to the accumulator.
- Now, the accumulator holds the value of the index register Y, which presumably holds some meaningful data about the current pixel or page.
- Then, the index register Y is incremented to prepare for the next memory location.
2.Add this instruction after the tya: lsr.What visual effect does this cause, and how many colours are on the screen? Why?
Adding the "lsr" instruction after "tya" in the provided bitmap code will perform a logical shift right operation on the accumulator. This operation shifts all bits in the accumulator one position to the right, effectively dividing its value by 2.
The more number of lsr commands you add the more logical shift right will occur. Eventually after 5 continous lsr commands the display looks like this.
These were the experiments that I performed but apart from these we can perform a lot of other experiments too.
Experiences with this Lab
Working on this lab has been an eye-opening experience for me. Delving into Assembly Language, especially with a processor like the 6502, offered a unique perspective on the intricacies of computer systems and programming.
Impressions of Assembly Language
At first glance, Assembly Language might seem daunting with its low-level syntax and direct manipulation of hardware. However, as I delved deeper, I discovered its beauty in simplicity and efficiency. Writing code at such a fundamental level provided a deeper understanding of how computers operate and how software interacts with hardware.
What I Learned
Throughout this lab, I learned not only about the technical aspects of Assembly Language but also about the importance of optimization and performance tuning. The process of optimizing code to reduce execution time was both challenging and rewarding. It taught me valuable lessons in problem-solving, critical thinking, and attention to detail.
Reflections on the Process
Reflecting on the process, I realized the significance of small optimizations and their impact on overall performance. The journey from the original bitmap code to the optimized version was a testament to the mantra "less is more" in Assembly Language programming. Every instruction, every cycle, and every byte mattered, emphasizing the importance of efficiency in code.
In addition, experimenting with instructions like "tya" and "lsr" provided insights into their functionalities and how they can be creatively used to achieve different visual effects. These experiments not only expanded my knowledge but also sparked my curiosity to explore further and push the boundaries of what can be achieved with Assembly Language.
Overall, this lab was not just about writing code; it was about embracing a mindset of optimization, exploring the nuances of Assembly Language, and gaining a deeper appreciation for the intricacies of computer programming.
Top comments (0)