sd:part_ii_writing_games_in_assembly_language
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| sd:part_ii_writing_games_in_assembly_language [2026/04/02 19:41] – appledog | sd:part_ii_writing_games_in_assembly_language [2026/04/03 05:30] (current) – appledog | ||
|---|---|---|---|
| Line 3: | Line 3: | ||
| == Introduction | == Introduction | ||
| - | At the end of [[SD-8516 Stellar BASIC]] we wrote a game called [[sdb: | + | At the end of [[SD-8516 Stellar BASIC]] we wrote a game called [[sdb: |
| == Part 1: Assembling and Running a Program | == Part 1: Assembling and Running a Program | ||
| - | An assembly language program should start with an .address | + | Just like BASIC programs have line numbers, or C programs have #include statements, an assembly language program should start with an '' |
| <codify armasm> | <codify armasm> | ||
| Line 216: | Line 216: | ||
| more to come... | more to come... | ||
| + | |||
| + | == Part 3: Player Input | ||
| + | Let's begin part 3 by adding a new subroutine to our main loop. Our main loop now becomes: | ||
| + | |||
| + | <codify armasm> | ||
| + | main_loop: | ||
| + | CALL @draw_map | ||
| + | CALL @get_input | ||
| + | RET | ||
| + | </ | ||
| + | |||
| + | === get_input | ||
| + | The primary goal of this section is to get input from the player and deal with it. We can do this by using the getkey function: | ||
| + | |||
| + | <codify armasm> | ||
| + | get_input: | ||
| + | LDAH $02 ; getkey() | ||
| + | INT $10 | ||
| + | </ | ||
| + | |||
| + | In this case, the function specification for AH=$02, INT 0x10 is: | ||
| + | |||
| + | ; ============================================================================ | ||
| + | ; AH=02h - Read Character (Blocking) | ||
| + | ; Input: | ||
| + | ; Output: AL = ASCII character | ||
| + | ; | ||
| + | ; | ||
| + | ; Note: X, Y preserved for cursor position | ||
| + | ; This function BLOCKS until a key is pressed | ||
| + | ; ============================================================================ | ||
| + | |||
| + | As we can see, this function returns the ASCII code of the key the player will press in '' | ||
| + | |||
| + | === uppercase or lowercase? | ||
| + | The player might type an uppercase command or a lowercase command. Let's normalize the keys to uppercase before processing them: | ||
| + | |||
| + | <codify armasm> | ||
| + | |||
| + | ; Uppercase: if AL >= ' | ||
| + | CMP AL, #97 | ||
| + | JNC @gi_check_keys | ||
| + | |||
| + | CMP AL, #123 | ||
| + | JC @gi_check_keys | ||
| + | | ||
| + | SUB AL, #32 | ||
| + | | ||
| + | gi_check_keys: | ||
| + | ... | ||
| + | </ | ||
| + | |||
| + | CMP works as follows: | ||
| + | |||
| + | CMP A, B ; if A >= B, then set carry | ||
| + | |||
| + | Therefore, | ||
| + | |||
| + | CMP AL, #97 ; if AL is greater or equal to #97 (' | ||
| + | |||
| + | So therefore if carry is NOT set, skip past the SUB command. Or else (if it's a lowercase ASCII) subtract 32 to convert from lowercase to uppercase. | ||
| + | |||
| + | The second compare has a protective function. | ||
| + | |||
| + | CMP AL, #123 ; if AL >= 123, set carry. | ||
| + | | ||
| + | ; If it's ' | ||
| + | JC @gi_check_keys | ||
| + | |||
| + | |||
| + | So after these two checks, the only values that reach SUB AL, #32 are exactly the bytes from 97 to 122 inclusive; i.e. ' | ||
| + | |||
| + | Visual summary: | ||
| + | ^ AL Value ^ Meaning ^ What Happens ^ | ||
| + | | < 97 | before '' | ||
| + | | 97-122 | '' | ||
| + | | >= 123 | after ' | ||
| + | |||
| + | === Processing player input | ||
| + | We will use the HJKL convention: | ||
| + | |||
| + | <codify armasm> | ||
| + | gi_check_keys: | ||
| + | CMP AL, #' | ||
| + | JZ @move_left | ||
| + | |||
| + | CMP AL, #' | ||
| + | JZ @move_down | ||
| + | |||
| + | CMP AL, #' | ||
| + | JZ @move_up | ||
| + | |||
| + | CMP AL, #' | ||
| + | JZ @move_right | ||
| + | |||
| + | CMP AL, #' | ||
| + | JZ @quit_game | ||
| + | |||
| + | RET | ||
| + | </ | ||
| + | |||
| + | This is easy enough; after a CMP, if the values are equal then the zero flag is set. We will use JZ (jump if zero flag is set) to go to the correct routine. | ||
| + | |||
| + | === processing each command | ||
| + | <codify armasm> | ||
| + | move_left: | ||
| + | LDAL [@PX] ; load variable PX into register AL. | ||
| + | DEC AL ; X = X - 1 (move to the left!) | ||
| + | | ||
| + | CMP AL, #1 ; bounds check. Is the player on the border? | ||
| + | JC @ml_ok | ||
| + | | ||
| + | LDAL #1 ; If we reach here the player was on the border; set position to 1. | ||
| + | | ||
| + | ml_ok: | ||
| + | STAL [@PX] ; pass! Save the player' | ||
| + | RET | ||
| + | </ | ||
| + | |||
| + | This is the move_left command. We begin by loading the player' | ||
sd/part_ii_writing_games_in_assembly_language.1775158901.txt.gz · Last modified: by appledog
