diff --git a/src/part2/bcd.md b/src/part2/bcd.md index eb6926f..bb5cac9 100644 --- a/src/part2/bcd.md +++ b/src/part2/bcd.md @@ -38,17 +38,21 @@ Don't worry about the call to `UpdateScoreBoard`, we'll get into that in a bit. ``` Let's have a look at what's going on there: -We set A to 1 and clear the carry flag -We add the score variable (contents of memory location `wScore`) to a, so now A has our increased score. + +First we store the score address (`wScore`) in HL. This allows us to use instructions like `LD A, [HL]` and `LD [HL], A`. In total this is 1 M-cycle and 1 byte more efficient than if we provided the address itself when loading and storing the score (`LD A, [wScore]` and `LD [wScore], A` respectively). + +Then we load the the score from that address into register A, the only register to be affected by `ADD`. This means that we can now increment it by 1 using exactly that instruction. So far so good, but what if the score was 9 and we add 1? The processor thinks in binary only and will do the following math: `%00001001` + `%00000001` = `%00001010` = `$A` That's a hexadecimal representation of 10, and we need to adjust it to become decimal. `DAA` or "Decimal Adjust after Addition," does just that. -After executing `DAA` our accumulator will be adjusted from `%00001010` to `%00010000`; a 1 in the left nibble and a 0 in the right one. A more detailed article about `DAA` on the Game Boy can be found [here](https://blog.ollien.com/posts/gb-daa/). +After executing `DAA` our accumulator will be adjusted from `%00001010` to `%00010000`; a 1 in the left nibble and a 0 in the right one. `DAA`'s exact behaviour is described [here](https://rgbds.gbdev.io/docs/master/gbz80.7#DAA). + +But why do we increment A using `ADD 1` when `INC A` does the same but is more efficient? That's because `DAA` evaluates the carry flag (see the linked description), but unlike `ADD`, `INC` does not affect that flag. So if the carry flag was still set from a previous operation, `DAA` would add 60 points. -Then we store the score back into `wScore` and finally, we call a function that will update the score board, which we will implement next. +Now that score (in A) has been properly incremented, we store it back into `wScore` and finally, we call a function that will update the score board, which we will implement next. Of course, we still need to call it on impact. To do this, we add a call to `IncreaseScorePackedBCD` after each collision handler (we had a left and a right collision) in `CheckAndHandleBrick` @@ -103,4 +107,4 @@ We then add the `DIGIT_OFFSET` constant to the tens digit to calculate the tile Finally, we repeat the process for the ones digit: We mask the tens digit from `A` using `and %00001111`, no need to rotate this time. -Now we can display the score on the screen! We'll need to call `UpdateScoreBoard` after each time the score is updated. We've already done this in the `IncreaseScorePackedBCD` function, so we're all set! \ No newline at end of file +Now we can display the score on the screen! We'll need to call `UpdateScoreBoard` after each time the score is updated. We've already done this in the `IncreaseScorePackedBCD` function, so we're all set! diff --git a/unbricked/bcd/main.asm b/unbricked/bcd/main.asm index 5f9747b..90d994c 100644 --- a/unbricked/bcd/main.asm +++ b/unbricked/bcd/main.asm @@ -294,11 +294,10 @@ IsWallTile: ; Increase score by 1 and store it as a 1 byte packed BCD number ; changes A and HL IncreaseScorePackedBCD: - xor a ; clear carry flag and a - inc a ; a = 1 - ld hl, wScore ; load score - adc [hl] ; add 1 - daa ; convert to BCD + ld hl, wScore ; load score address for faster access + ld a, [hl] ; load score to accumulator + add 1 + daa ; make sure it's a BCD ld [hl], a ; store score call UpdateScoreBoard ret @@ -754,4 +753,4 @@ wBallMomentumY: db ; ANCHOR: score-variable SECTION "Score", WRAM0 wScore: db -; ANCHOR_END: score-variable \ No newline at end of file +; ANCHOR_END: score-variable