First Try at Coding in Assembly Language
Recently, I had the opportunity to code in assembly language. The coding was done on an emulator based off of the 6502 chip. There are 56 predetermined set of instructions for the 6502 emulator such as load accumulator (lda) and store accumulator (sta). In this blog, I will add several instructions to modify the code and see the visual affects that will take place. At the end, there will be an attempt at creating a box around the 32 x 32 bitmap.
The Bitmap Code
lda #$00 ; set a pointer at $40 to point to $0200 sta $40 lda #$02 sta $41 lda #$07 ; colour ldy #$00 ; set index to 0 loop: sta ($40),y ; set pixel iny ; increment index bne loop ; continue until done the page inc $41 ; increment the page ldx $41 ; get the page cpx #$06 ; compare with 6 bne loop ; continue until done all pages
The Bitmap Code Modifications
Transfer to Accumulator Instruction (tya)
The first modification will involve the transfer y to accumulator instruction (tya). This will produce a range of colors from $0 – $f. The y register currently has the value #$00 in its memory, which is the value the represents black. Accumulator originally has the value #$07, which is yellow, but after the instruction tya, the accumulator registry now holds the value #$00. Each time iny (increase y) is called, the value in the y register memory is increase (#$01, #$02, etc.) and transferred to the accumulator’s register memory. Thus, across the bitmap screen, all 16 colors will be displayed twice.
Logical Shift Right Instruction (lsr)
The second modification was to add another instruction, lsr (logical shift right), right after the tya (transfer y to accumulator). What occurred was that the y register, which contained the current bit location of the bitmap in hex format, started at 0000 and would get increased to 0001 and transferred to the accumulator register. When lsr was added, the 1 would be shifted to the right, which set the accumulator register to be at 0000. For clarification, when the y register is incremented to 0010 and 0011 and transferred via tya, the logical shift right would change it to 0001 and 0001, respectively. Thus, when y register increases, the index moves to the next column, but the accumulator register gets logically shifted to the right which causes the same color to be set into two columns. When adding another lsr to the code it created an instance where 4 pixels would be filled with the same color because the lsr would shift the 1 two spots to the right, effectively doubling the amount of pixels that one lsr would cover from 2 to 4. For example, a logical shift for 0000, 0001, 0010, and 0011 would be 0000, 0000, 0000, 0000 respectively, when there are two logical shifts to the right. Thus, the color black would be set each time y register is incremented. When there are 3 logical right shits in succession, it would shift three spots to the right. Therefore, when the color, in the accumulator registry, would get incremented, the bits would get shifted right, doubling the amount of pixels covered from 4 to 8. Thus, we have one color covering 8 pixels before a new color is set in the bitmap. With 4 logical right shifts, it would double the amount of pixels covered from 8 to 16. Finally, with 5 logical right shifts, the amount of pixels covered would increase from 16 to 32, causing each row to be a different color until all 16 colors are drawn, then it would reset back to the first color, 0000 (black).
Arithmetic Shift Left (lsr)
The third modification was to use asl (Arithmetic shift left) to replace lsr (Logical shift right). Similar to the Logical shift right above, but instead the 1 is shifted to the left. For example, 0000, 0001, 0010, 0011 would be 0000 (black), 0010 (red), 0100 (purple), 0110 (blue) respectively. By adding another asl, it would change to every 4th color instead of every 2nd. When 3 arithmetic shift lefts are added, the 1 would be shifted 3 spots. Since we are only dealing with significant bits, any bits that are shifted too far to the left are discarded. For example, 0011 (3) would be 0000 (0) because the 1’s are discarded due to 3 left shifts. This is the reason why when there are 3 asl, only two colors are displayed. With 4 asl, all the 1’s are discarded and we are left with 0000. Thus, the screen is set to black. When there are 5 asl, it has the same effect as with 4. The 1’s in the significant bits are discarded. Thus, we have a black bitmap.
Increment y (iny)
The fourth modification was removing all tya, asl, and lsr, replacing the instructions with iny (increment y). When we have a total of two iny, it would color in every 2nd pixel. In this instance y begins at 00, but with 2 iny, the next time it sets the color yellow is when y is at 02. When there are 3 iny, the program would fill in every third. We see it fill in like a checkered pattern because the bne would not break until the end of the page is reached. If the ending of the page is 1f, the program could try to color in the last pixel and have 2 remaining , which would carry over to the next row. Thus, until index y is equal to zero and breaks the branch, the program would continue filling in on the next line. With 4 iny, the amount of pixels skipped are even. Thus, zero can be reached for each row and the program would set the y index to yellow. Similar to when there were 3 iny, but with 5 iny, each row gets filled in slower. While 4 iny fills 12 pixels in a row each loop, 5 iny would only fill 8 pixels per row before moving onto the next row. Thus, the visual effect looks slower when filling the bitmap with 5 iny and faster with 3 iny.
Drawing A Box
; === green top lda #$00 sta $10 lda #$02 sta $11 lda #$0d ldy #$00 top: sta $0200,y iny cpy #$20 bne top ; === blue bottom lda #$0e ldy #$00 bottom: sta $05e0,y iny cpy #$20 bne bottom ; ==== red left lda #$00 sta $10 lda #$02 sta $11 ldy #$00 left: lda #$02 sta ($10),y ;add 20 to pointer lda $10 clc adc #$20 sta $10 bcc left inc $11 lda $11 cmp #$06 bne left ; === purple right lda #$1f sta $10 lda #$02 sta $11 ldy #$00 right: lda #$04 sta ($10),y lda $10 clc adc #$20 sta $10 bcc right inc $11 lda $11 cmp #$06 bne right
The code provided above is broken into 4 different sections. The first section is a green top border, the second is a blue bottom border, the third is a red left border, and the fourth is a purple right border.
When creating the green top border, line 1-5 represents a pointer created for memory location 10 and 11 with the values 00 and 02 respectively. The back end will rearrange these numbers to $0200. 02 represents the current page, while 00 represents the first index of the page. Line 8 represents the beginning of drawing where sta $0200, y stores memory location 0200 and the value inside the y register inside the accumulator register. The loop will run and set the pixel to green every increment of y until the end of the row is reached. Once the end of the row is reached, line 12 will be exit.
The blue bottom border is the same as the green top border, but the starting point for would be changed. Looking at line 18, it was changed from originally 0200 to 05e0 to represent the starting point on page 5 at the index e0 which starts on first pixel of last row, on last page.
The red left border is created by first storing the y register into the accumulator register. Once that is done, on line 32 – 35, we load the accumulator with the current pixel position (00), then we add 20 to the current value in accumulator to get to the next line (64 bits in decimal is 20 in hex). Thus, every time the program sets a color, it will add 20 to current accumulator value to point to the next row. On line 33, clc (clear carry) is used to remove the overflow flag at the end of 20 before we add because if we did not do this, it would add 20 + 1 (overflow flag) which would set the next row one pixel to the right. Line 35 stores the current accumulator value after the addition. Line 37-39 is a branch loop that cycles through all the pages until page 6 is found and then stops drawing the red border.
The purple right is created using the same instructions as the red left border, but accumulator register is loaded with $1f to start at the end of the row instead of the beginning.
I found that the task of drawing a box around the 32 x 32 bitmap gave me insight into memory location. In order to get the pixel to draw at the bottom, right, and left border, we would need to store a value that represented the memory 00 to 1f. I had trouble where when I disassembled the code, it would show bugs in the disassembly column (???). This represented that the code after I ran caused an error because the program would go pass page 5. In conclusion, I found that this task of drawing a box helped with understanding the syntax involved in using instruction sets, the difference between an integer with a prefix of #$ and $ and the functions of each instruction set.