DEV Community

JP
JP

Posted on

Assembly Loops, Bit Shifts, and More!

Introduction

As an introduction to software portability, I get to experiment with 6502 assembly code via an emulator. The lab is focussed on handling bytes located on registries and memory. Processors have a unique set of instructions. A subset of these instructions are manage the memory within, to, and from the registries and memory.

A visualizer can be found in the emulator where each pixel represents a specific address in memory.

Compared to the modern processor the 6502 is a “simple” processor but is still capable. The simplicity of the instruction set serves as a wonderful introduction into writing, understanding, and analyzing the time complexity of assembly code.

; 6502 Instruction Set
ADC AND ASL BCC BCS BEQ BIT
BMI BNE BPL BRK BVC BVS CLC
CLD CLI CLV CMP CPX CPY DEC
DEX DEY EOR INC INX INY JMP
JSR LDA LDX LDY LSR NOP ORA
PHA PHP PLA PLP ROL ROR RTI
RTS SBC SEC SED SEI STA STX
STY TAX TAY TSX TXA TXS TYA
Enter fullscreen mode Exit fullscreen mode

Let’s get started! Here’s a sample of 6502 assembly code given in the lab notes, let’s break it down a couple lines at a time.

    lda #$00
    sta $40
    lda #$02    
    sta $41
    lda #$07
    ldy #$00
 loop:  sta ($40),y
    iny
    bne loop
    inc $41
    ldx $41
    cpx #$06
    bne loop
Enter fullscreen mode Exit fullscreen mode

Understanding 6502 Assembly Code

Before we start looking at the code, let’s understand the 6502 assembly syntax.

  • #x: represents an immediate operand value.
  • $: prefix to represents a hexadecimal value.
  • (): represents an indirect address, accessing memory indirectly by referencing an address in another location.
    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
Enter fullscreen mode Exit fullscreen mode

Loading Values into the Registries

The first couple of lines contain 3 unique instructions - lda, sta, ldy. Here’s an overview of each instruction:

Assembly Name Description
lda Load Accumulator with Memory Transfer data from memory into the accumulator register.

Memory → Accumulator register |
| sta | Store Accumulator in Memory | Transfer data from accumulator into memory.

Accumulator register → Memory |
| ldy | Load Index Registry Y from Memory | Transfer data from memory into the Y register.

Y register → Memory |

Lines 1-2 loads 00 into the accumulator registry (i.e. lda #$00), then the accumulator value is stored into the memory location 40 . The same processes is repeated for value 41 . Note that 6502 adopts a little-endian system, where bytes are read from right to left.

Loop

 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
Enter fullscreen mode Exit fullscreen mode

Let’s review the instructions in this snippet:

Assembly Name Description
iny Increment Index Register Y by One Add one to the current value stored in registry Y.
bne Branch on Result Not Zero Conditional, branch to an specified address if the Z-flag equals 0.
inc Increment Memory by One Add one to the contents of the addressed memory location.
ldx Load Index Register X From Memory Load the index register X from memory.
cpx Compare Index Register X to Memory Compare the value in the X register with a value in memory or an immediate value.

Inner Loop: Filling the Page with Yellow Pixels

The inner loop starts by calculating where to store the current accumulator value. This is done by adding the value located in the memory address 40 and the value in the y register, which are 00 and 00 respectively. In the first iteration it will fill memory address with the value 07 , stored in the accumulator register, which corresponds to yellow, then do the same with memory address 0201, etc.

Once the loop reaches the max page size of 256, incrementing it will loop back to 00 — flagging the bne instruction to branch off.

Outer Loop: Switching Pages

The outer loop controls which page we are currently on. Remember that we start in page 2 (i.e. 02 ) and is stored in memory address 41 . The outer loops starts by incrementing the page number by 1 via inc $41 and then is loaded into the x register where we check if it equal to 6 (i.e. cpx #$06).

Notice how we start from page 2 and stop at page 5 ( i.e. [2, 6)). Where the page technically gets incremented to the value 6 but cpx $#06 exits the loops, finishing the program instructions.

Now that we understand what the code does, running it will fill the visualizer with yellow pixels!

Image description

Code Analysis

Time Complexity

The performance of 6502 assembly code can be quantified by the number of cycles it takes the processor to perform the given instructions. Remember that the 6502 processor has 56 instructions, each of these instructions have a cycle count associated with it.

Below is a table that contain the instruction used in our program with its respective cycle count.

Instruction Cycles Cycle Count Alt Cycles Alt Count Total
LDA #$00 2 1 0 0 2
STA $40 3 1 0 0 3
LDA #$02 2 1 0 0 2
STA $41 3 1 0 0 3
LDA #$07 2 1 0 0 2
LDY #$00 2 1 0 0 2
loop: STA ($40), y 6 256 0 0 1536
INY 2 256 0 0 512
BNE loop 3 255 2 1 767
INC $41 5 4 0 0 30
LDX $41 3 4 0 0 18
CPX #06 2 4 0 0 12
BNE loop 3 3 2 1 17

Before we start calculating, let’s understand what each column in the table mean.

  • Cycles — number of cycles for the instruction to finish executing
  • Cycle Count — number of times the instruction runs
  • Alt Cycles — number of additional cycles the instruction runs, depends on specific conditions
  • Alt Count — number of times the Alt Cycle runs

Initializing Values

The first 6 instructions are only executed once since they “initialize” the starting values of where the memory starts and the offset.

Initializing Values = 14 cycles
Enter fullscreen mode Exit fullscreen mode

Inner Loop

The inner loop starting, lines 7- 9, fill the byte with a yellow pixel, and runs 256 times to fill each byte in the page. However on the 256th iteration, BNE branches giving it a cycle count of 2 instead of 3.

Inner Loop = 255 * (6 + 2 + 3) + 1 * (6 + 2 + 2)
           = 2805 + 10
Enter fullscreen mode Exit fullscreen mode

Note: this calculation is only for a single page.

Outer Loop

The outer loop, lines 10-13, switches the page. However on the last page, BNE branches giving it a cycle count of 2 instead of 3.

Here’s a more in-depth calculation:

Outer Loop = 3 * (5 + 3 + 2 + 3) + 1 * (5 + 3 + 2 + 2)
           = 31 + 12
           = 51 cycles
Enter fullscreen mode Exit fullscreen mode

Total

Putting it all together:

Total = Initializing Values + Inner Loop * 4 Pages + Outer Loop
      = 14 + (2815 * 4) + 51
      = **11325 cycles**
Enter fullscreen mode Exit fullscreen mode

Performance

The 6502 processor runs at a clock speed of 1Mhz, where each cycle takes 1 microsecond to complete. Let’s calculate the programs performance.

Program cycle count = 11325 Cycles
Clock Speed = 1 Mhz
===================================
Time to complete = Program cycle count / Clock speed (Hz)
                 = 11325 Cycles / (1000000 Cycles / second)
                   = 0.011325 seconds

Time to complete = 0.011325 seconds = 11.325 milliseconds
Enter fullscreen mode Exit fullscreen mode

Memory Complexity

The 6502 processor has a total of 256 pages where each page has 256 bytes, with a grand total of 65536 bytes of memory. Note that page 0 is optimized for 0 page addressing and page 1 is reserved for the stack.

Our program is utilizing the memory in 3 ways — the assembly instructions, written values, and pointer memory.

Assembly Instructions

Each instruction in the program uses memory when executed, below is the associated memory to the instructions in the program.

Instruction Bytes
LDA #$00 2
STA $40 2
LDA #$02 2
STA $41 2
LDA #$07 2
LDY #$00 2
loop: STA ($40), y 2
INY 1
BNE loop 2
INC $41 2
LDX $41 2
CPX #06 2
BNE loop 2
Assembly instruction memory = 2 + 2 + 2 + 2 + 2 + 2 + 2 + 1 + 2 + 2 + 2 + 2 + 2
                           = 25 bytes
Enter fullscreen mode Exit fullscreen mode

Summing the bytes from each instruction is a total of 25 bytes

Written Values

As we’ve seen multiple times, the program stores 07 into all the bytes of pages 2 to 5, and each page is 256 bytes.

Written values memory = 256 * 4
                                         = 1024 bytes
Enter fullscreen mode Exit fullscreen mode

The program writes to 1024 bytes

Pointers

In the beginning of the program we dedicate memory for the pointers to store the base address (i.e. $40 and $41).

Pointer memory = 1 + 1 
               = 2
Enter fullscreen mode Exit fullscreen mode

Total Memory

Adding each of the ways the program uses memory, we have a grand total of 1051 bytes of memory.

Total memory usage = Assembly instructions + Written values + Pointers
                   = 25 + 1024 + 2
                   = 1051 bytes
Enter fullscreen mode Exit fullscreen mode

Optimization and Modification

Optimization

The current code uses 2 loops, one to go through each address in the current and another to increment the page. Notice that each page has the same number of addresses, therefore, we can use the offset to set the pixel for all 4 pages at the same. This works because the low-byte of each address is the same for each page, and since we know which pages map to the bitmap visualizer we can use the absolute value, rather than a reference.

    lda #$07        ; Set color yellow
    ldy #$00        ; Start with offset of 0

loop:
    sta $0200, y    ; Set pixel for page 2
    sta $0300, y    ; Set pixel for page 3
    sta $0400, y    ; Set pixel for page 4
    sta $0500, y    ; Set pixel for page 5
    iny             ; Increment the offset

    bne loop        ; Loop until overflow back to 00
Enter fullscreen mode Exit fullscreen mode

Note that there is a single loop, reducing the runtime significantly. In terms of Big O notation, this reduces the runtime from O(n^2) to O(n). Let’s calculate the number of cycles.

Instruction Cycles Cycle Count Alt Cycles Alt Count Total
LDA #$07 2 1 0 0 2
LDA #$00 2 1 0 0 2
loop: STA $0200, y 5 256 0 0 1280
loop: STA $0300, y 5 256 0 0 1280
loop: STA $0400, y 5 256 0 0 1280
loop: STA $0500, y 5 256 0 0 1280
INY 2 256 0 0 512
BNE loop 3 3 2 1 767
Total Cycles = 2 + 2 + (1280 * 4) + 512 + 767
             = **6403 cycles**
Enter fullscreen mode Exit fullscreen mode
Percentage Reduction = (Original Cycle Count - Optimized Cycle Count) / Original Cycle Count) * 100
                     = (11325 - 6403) / 11325 * 100
                     = 0.4356 * 100
                     = **43.46 %**
Enter fullscreen mode Exit fullscreen mode

With the optimization, cycle count has been reduced by approximately 43%! In my opinion, the code does look cleaner, but as instructions get more complex, the absolute values addressing the pages may not work.

Modifications

Modification 1: Change the Pixels to Light Blue

The value for light blue can be found in the “Notes” output in the console. $e corresponds to light blue. Let’s change the accumulator value to $e in our optimized code and observe the difference.

    lda $0e        ; Set color light blue
    ldy #$00        ; Start with offset of 0

loop:
    sta $0200, y    ; Set pixel for page 2
    sta $0300, y    ; Set pixel for page 3
    sta $0400, y    ; Set pixel for page 4
    sta $0500, y    ; Set pixel for page 5
    iny             ; Increment the offset

    bne loop        ; Loop until overflow back to 00
Enter fullscreen mode Exit fullscreen mode

Light blue Bitmap

Modification 2: Different Colours for each Page

We can modify the original code to use the high-byte value for the colour code rather than a static value. Therefore, the first page (page 2) will use colour value $02 which is a red, then page 3 will use colour value $03 which is cyan, etc.

    lda #$00       ; Set pointer to $0200
    sta $40        ; Low byte in $40
    lda #$02       ; Set high byte of the pointer
    sta $41        ; High byte in $41
    ldy #$00       
loop:   
    lda $41        ; Use high byte as the color code
    sta ($40),y    ; Set pixel color at (pointer)+Y using high byte
    iny            ; Increment Y index
    bne loop       

    inc $41        ; Increment page
    cmp #$06       
    bne loop       

Enter fullscreen mode Exit fullscreen mode

Different Colours for each Page

Modification 2: Random Colour for each Pixel

We can modify the original code to generate a random colour in each iteration. From the “Notes” section from the emulator,
* Memory location $fe contains a new random byte on every read.

$fe can be used to get a random byte (i.e. colour) at each iteration.

      lda #$00        ; Set a pointer in memory location $40                                           
      sta $40         ; Low byte ($00) goes in address $40
      lda #$02        ; High byte ($02) goes into address $41
      sta $41
      ldy #$00        ; Set index to 0

loop: sta ($40), y    ; Set pixel color at the address 
                      ;  (pointer)+Y
      lda $fe     ; get a random color
      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
Enter fullscreen mode Exit fullscreen mode

Random Colour for each Byte
Image description

Experiments

Now that we understand the assembly code, lets perform a number of experiments.

Experiment 1: tya Instruction

Let’s begin by adding tya , transfer index Y to accumulator, instruction to the inner loop.

    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:  tya ; ** NEW **, transfer index Y into accumulator
  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
Enter fullscreen mode Exit fullscreen mode

With a single instruction, we change the result to have vertical stripes of repeating colours, starting with black, white, burgundy, aqua, etc. Monitoring the memory starting at 0200, we can see the pattern in the values stored in each page:

       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
0200: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
0210: 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
0220: 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
0230: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
0240: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
0250: 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
0260: 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
0270: 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
0280: 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f
0290: 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f
02a0: a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af
02b0: b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf
02c0: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf
02d0: d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df
02e0: e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef
02f0: f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff
Enter fullscreen mode Exit fullscreen mode

In the assembly code, the value in the Y register is loaded into the accumulator, replacing the the initial value of 07. Entering the loop, the Y value is now used as both the low byte, and the page offset — this can be seen in the matrix above, where the column value (i.e. offset value) is the same as the low byte.

If we look at the notes section of the simulator the Y value corresponds to the colour on the visualizer.

$0: Black
$1: White
$2: Red
...
$d: Light green
$e: Light blue
$f: Light grey
Enter fullscreen mode Exit fullscreen mode

Experiment 2: lsr Instruction

Let’s add the lsr, logical shift right, instruction immediately after tya added in the previous experiment

    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:  tya ; transfer index Y into accumulator
  **lsr ; ** NEW **, logical shift right**
  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
Enter fullscreen mode Exit fullscreen mode

Image description

With lsr, instead of each colour appearing twice, each colour appears only once with each vertical line being 1 pixel wider. By default, lsr shifts the accumulator value to the right by 1 bit. This behaviour can be seen when monitoring the pages:

       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
0200: 00 00 01 01 02 02 03 03 04 04 05 05 06 06 07 07
0210: 08 08 09 09 0a 0a 0b 0b 0c 0c 0d 0d 0e 0e 0f 0f
0220: 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17
0230: 18 18 19 19 1a 1a 1b 1b 1c 1c 1d 1d 1e 1e 1f 1f
0240: 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 27
0250: 28 28 29 29 2a 2a 2b 2b 2c 2c 2d 2d 2e 2e 2f 2f
0260: 30 30 31 31 32 32 33 33 34 34 35 35 36 36 37 37
0270: 38 38 39 39 3a 3a 3b 3b 3c 3c 3d 3d 3e 3e 3f 3f
0280: 40 40 41 41 42 42 43 43 44 44 45 45 46 46 47 47
0290: 48 48 49 49 4a 4a 4b 4b 4c 4c 4d 4d 4e 4e 4f 4f
02a0: 50 50 51 51 52 52 53 53 54 54 55 55 56 56 57 57
02b0: 58 58 59 59 5a 5a 5b 5b 5c 5c 5d 5d 5e 5e 5f 5f
02c0: 60 60 61 61 62 62 63 63 64 64 65 65 66 66 67 67
02d0: 68 68 69 69 6a 6a 6b 6b 6c 6c 6d 6d 6e 6e 6f 6f
02e0: 70 70 71 71 72 72 73 73 74 74 75 75 76 76 77 77
02f0: 78 78 79 79 7a 7a 7b 7b 7c 7c 7d 7d 7e 7e 7f 7f
Enter fullscreen mode Exit fullscreen mode

lsr shifts the bits to the right by removing the right most bit and in this case, inserts a 0 to the left most position. If we walk-through the first 3 iterations:

  1. Iteration 1:
    1. Y = A = 0000 = 0000 0000
    2. After lsr: 00 = 0000 000000 = 0000 0000
      1. Note: nothing changes
  2. Iteration 2:
    1. Y = A = 0101 = 0000 0001
    2. After lsr: 01 = 0000 000100 = 0000 0000
  3. Iteration 3:
    1. Y = A = 0202 = 0000 0010
    2. After lsr: 02 = 0000 001001 = 0000 0001

These calculated values correspond their respective memory addresses. (e.g. 0200 - 0202).

Experiment 2a: Repeating lsr Instructions

Let’s repeat the lsr instructions multiple times. Given what we know about lsr, the bits should shift x amount of times to the right, where x is the number of repeated lsr instructions.

Initially, I thought repeating lsr once will (i.e. 2 lsr in succession) will widen the lines by a factor of 2 but I was partly wrong. If we look at the image the same way the program loops, moving left to right, then top to bottom, we see that the colours are doubling in width. What I didn’t expect is the alternating pattern of colours.

Image description

The alternating colour pattern is due to right shift, where the width would increase 2^x times before going to the next colour.

Let’s repeat this with 3 to 5 lsr instructions in succession. Given our observations, we should see the colour cover 8, 16, then 32 pixels wide, before going to the next colour.

3  raw `lsr` endraw
3 lsr

4  raw `lsr` endraw
4 lsr

5  raw `lsr` endraw
5 lsr

If we observe closely, the pattern is always black, white, burgundy, cyan, etc.

Experiment 2a: Repeating asl Instructions

Let’s repeat the lsr experiment but replace lsr with asl. asl, arithmetic shift left, shifting the bits to the left once. It completes this in a similar way, where the right most bit is removed and in this case a 0 is inserted to the most right.

Let’s run through the first 3 iterations where one asl is in the loop:

  1. Iteration 1:
    1. Y = A = 0000 = 0000 0000
    2. After asl: 00 = 0000 000000 = 0000 0000
      1. Note: nothing changes
  2. Iteration 2:
    1. Y = A = 0101 = 0000 0001
    2. After asl: 01 = 0000 000102 = 0000 0010
  3. Iteration 3:
    1. Y = A = 0202 = 0000 0010
    2. After asl: 02 = 0000 010004 = 0000 0100

This pattern can be observed in the memory map:

       0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
0200: **00 02 04** 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e
0210: 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e
0220: 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e
0230: 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e
0240: 80 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e
0250: a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 b6 b8 ba bc be
0260: c0 c2 c4 c6 c8 ca cc ce d0 d2 d4 d6 d8 da dc de
0270: e0 e2 e4 e6 e8 ea ec ee f0 f2 f4 f6 f8 fa fc fe
0280: 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e
0290: 20 22 24 26 28 2a 2c 2e 30 32 34 36 38 3a 3c 3e
02a0: 40 42 44 46 48 4a 4c 4e 50 52 54 56 58 5a 5c 5e
02b0: 60 62 64 66 68 6a 6c 6e 70 72 74 76 78 7a 7c 7e
02c0: 80 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e
02d0: a0 a2 a4 a6 a8 aa ac ae b0 b2 b4 b6 b8 ba bc be
02e0: c0 c2 c4 c6 c8 ca cc ce d0 d2 d4 d6 d8 da dc de
02f0: e0 e2 e4 e6 e8 ea ec ee f0 f2 f4 f6 f8 fa fc fe
Enter fullscreen mode Exit fullscreen mode

1  raw `asl` endraw
1 asl

One interesting observation are the differences in colours between asl and lsr. Since we are shifting bits to the left, the colour values are increasing by a factor of 2 (e.g. 2x where x is the number of asl instructions in succession).

The values resulting in asl will always be of base 2, which explains the colour pattern of black ($0), red ($2), purple ($4), etc. with 1 asl the pattern ends with blue ($e). Given the pattern, I expect the pattern to shorten by a factor of 2 because each value will be doubled (e.g. $02$04, $04$08, etc.).

Let’s continue by adding the remaining asl instructions:

2  raw `asl` endraw
2 asl

3  raw `asl` endraw
3 asl

4  raw `asl` endraw
4 asl

5  raw `asl` endraw
5 asl

Notice at 4 and 5 asl, it is filled with all black pixels. Shifting bits the to left 4+ times will being the value into the second byte, leaving the first byte to the filled with 0’s. For example let’s apply asl 4 times to 01.

01 = 0000 000110 = 0001 0000. The second byte will be displayed in the bitmap visualizer, with 0 being a black pixel. We can see that the 1 that starting in the first byte has been shifted into the second byte - leaving the first byte to be replaced with all 0’s.

Experiment 3: Repeating iny Instructions

We’ve seen iny in the previous section where it was used to increment the memory address of a page. Let’s add more iny instructions and observe the bitmap visualizer changes.

2  raw `iny` endraw
2 iny

3  raw `iny` endraw
3 iny

4  raw `iny` endraw
4 iny

5  raw `iny` endraw
5 iny

One key observation is the run animation of the when there are odd number of iny instructions. With 3, each page is being passed through 3 times before moving to the next page. The same observation is made when there are 5 iny instructions, where a page would be passed through 5 times before moving to the next page.

When it comes to even number of iny instructions, the bitmap displays vertical stripes but the larger the step, the wider the black stripe becomes.

This pattern can be understood by the relationship by calculating the modulus. Let’s use 3 and 2. 255 mod 3 = 0, with no remainder it means all memory addresses will be filled. 255 mod 2 = 1, with a remainder of 1, it means that every other memory address is skipped. This explains why we get a vertical stripe pattern with even numbers.

Conclusion

In this lab, we wrote some assembly to understand the flow of data between registers, and memory! Comparing assembly to high level programming languages (e.g. Python, JavaScript), a lot can go wrong since there isn’t a “safety” net that warns you about potential issues before running the code.

Dealing with memory in general can be tricky since you need to facilitate the movement, allocation, and deallocation. With my current knowledge I expect memory management strategies to be similar to C/C++.

The shifting of bits to the left or right was a completely new concept and found it interesting how such a “small” change is responsible for a large change, in this lab it can change an pixel to a completely different colour. I imagine in larger, complex programs, bit shifting can cause a catastrophic event. I’m excited to use this knowledge in preparation for the next lab! See you soon!

Top comments (0)