diff options
| author | Miquel Sabaté Solà <msabate@suse.com> | 2023-11-27 10:31:03 +0100 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-02-04 21:02:54 +0100 |
| commit | cee93625989b651cfe91387eabd0abd3f64a00df (patch) | |
| tree | d1525bd15c191c2926ea1166263b249a8bbeb79c /scroll/include | |
| parent | 0e1839f48ada69b81f5879449d0e0fe435f851c5 (diff) | |
| download | code.nes-cee93625989b651cfe91387eabd0abd3f64a00df.tar.gz code.nes-cee93625989b651cfe91387eabd0abd3f64a00df.zip | |
scroll: Start with the scrolling examples
This is still work in progress but at least there's some basic structure
to it.
Signed-off-by: Miquel Sabaté Solà <msabate@suse.com>
Diffstat (limited to 'scroll/include')
| -rw-r--r-- | scroll/include/apu.s | 6 | ||||
| -rw-r--r-- | scroll/include/globals.s | 43 | ||||
| -rw-r--r-- | scroll/include/joypad.s | 63 | ||||
| -rw-r--r-- | scroll/include/oam.s | 13 | ||||
| -rw-r--r-- | scroll/include/palettes.s | 30 | ||||
| -rw-r--r-- | scroll/include/player.s | 88 | ||||
| -rw-r--r-- | scroll/include/ppu.s | 27 |
7 files changed, 270 insertions, 0 deletions
diff --git a/scroll/include/apu.s b/scroll/include/apu.s new file mode 100644 index 0000000..32ccff2 --- /dev/null +++ b/scroll/include/apu.s @@ -0,0 +1,6 @@ +.segment "CODE" + +.scope APU + DMC = $4010 + FRAME_COUNTER = $4017 +.endscope diff --git a/scroll/include/globals.s b/scroll/include/globals.s new file mode 100644 index 0000000..d941736 --- /dev/null +++ b/scroll/include/globals.s @@ -0,0 +1,43 @@ +;; Resets the background buffer to a zero-sized array. +.macro CLEAR_BACKGROUND_BUFFER + lda #$FF + sta Globals::m_background_buffer +.endmacro + +;; TODO: macro PUSH_TO_BACKGROUND_BUFFER_X + +;; Global variables used throughout the scrolling examples. +.scope Globals + ;;; + ;; Temporary values. + + m_tmp_1 = $90 + m_tmp_2 = $91 + m_tmp_3 = $92 + + ;; Current value for the scroll on the X axis. + m_scroll = $93 + + m_background_idx = $19 + + ;; TODO + m_collisions = $20 + + ;; TODO + m_background_buffer = $40 + + ;; Initialize global variables. + .proc init + lda #0 + sta m_tmp_1 + sta m_tmp_2 + sta m_tmp_3 + sta m_scroll + sta m_background_idx + + CLEAR_BACKGROUND_BUFFER + sta m_collisions + + rts + .endproc +.endscope diff --git a/scroll/include/joypad.s b/scroll/include/joypad.s new file mode 100644 index 0000000..8711c28 --- /dev/null +++ b/scroll/include/joypad.s @@ -0,0 +1,63 @@ +.segment "CODE" + +;;; +;; Joypad controller code. The following memory addresses are reserved: $21-$23. +;; +;; Memory address $21 is used for internal purposes, whereas $22 and $23 contain +;; the bitmask of the buttons that are pressed from each controller. +;;; + +.scope Joypad + ;; Button masks. + BUTTON_A = 1 << 7 + BUTTON_B = 1 << 6 + BUTTON_SELECT = 1 << 5 + BUTTON_START = 1 << 4 + BUTTON_UP = 1 << 3 + BUTTON_DOWN = 1 << 2 + BUTTON_LEFT = 1 << 1 + BUTTON_RIGHT = 1 << 0 + + ;; Port addresses for controllers. + JOYPAD1 = $4016 + JOYPAD2 = $4017 + + ;; We keep all the information from controller from mainly two variables: + ;; m_buttons1 and m_buttons2; containing respectively the buttons pressed + ;; for this frame for both controllers. The m_inv_buttons ($21) is an + ;; internal variable and should not be used for anything outside of this + ;; usage. + m_inv_buttons = $21 + m_buttons1 = $22 + m_buttons2 = $23 + + ;; READ_CONTROLLER reads the input from the controller mapped into the given + ;; port, and saves the state into the given `buttons` address. + ;; Implementation taken from NESHacker's example of smb3-like movement. + .macro READ_CONTROLLER port, buttons + lda m_inv_buttons + tay + lda #1 + sta port + sta m_inv_buttons + lsr + sta port + : + lda port + lsr + rol m_inv_buttons + bcc :- + tya + eor m_inv_buttons + and m_inv_buttons + sta buttons + .endmacro + + ;; read sets the values for m_buttons1 and m_buttons2 as read from both + ;; controllers. + .proc read + READ_CONTROLLER JOYPAD1, m_buttons1 + READ_CONTROLLER JOYPAD2, m_buttons2 + rts + .endproc +.endscope diff --git a/scroll/include/oam.s b/scroll/include/oam.s new file mode 100644 index 0000000..ecd1b7d --- /dev/null +++ b/scroll/include/oam.s @@ -0,0 +1,13 @@ +.segment "CODE" + +.scope OAM + ADDR = $2003 + DMA = $4014 +.endscope + +.macro OAM_WRITE_SPRITES + lda #$00 + sta OAM::ADDR + lda #$02 + sta OAM::DMA +.endmacro diff --git a/scroll/include/palettes.s b/scroll/include/palettes.s new file mode 100644 index 0000000..9403b7b --- /dev/null +++ b/scroll/include/palettes.s @@ -0,0 +1,30 @@ +;; Shared code for palettes across scrolling examples. +.scope Palettes + DEFAULT_COLOR = $11 + + ;; Copies all the palettes for our game into the proper PPU address. + .proc init + PPU_ADDR $3F00 + + ldx #0 + @load_palettes_loop: + lda palettes, x + sta PPU::DATA + inx + cpx #$20 + bne @load_palettes_loop + rts + palettes: + ;; Background + .byte DEFAULT_COLOR, $36, $17, $0F + .byte DEFAULT_COLOR, $00, $00, $00 + .byte DEFAULT_COLOR, $00, $00, $00 + .byte DEFAULT_COLOR, $00, $00, $00 + + ;; Foreground + .byte DEFAULT_COLOR, $28, $0F, $30 + .byte DEFAULT_COLOR, $00, $00, $00 + .byte DEFAULT_COLOR, $00, $00, $00 + .byte DEFAULT_COLOR, $00, $00, $00 + .endproc +.endscope diff --git a/scroll/include/player.s b/scroll/include/player.s new file mode 100644 index 0000000..95d710d --- /dev/null +++ b/scroll/include/player.s @@ -0,0 +1,88 @@ +;; This is the player code that gets re-used on all scrolling examples. This +;; will show a meta-sprite made up of four sprites that make up diskun. You can +;; move this player with the arrows, and the movement will be pretty basic (1 +;; pixel each time). Furthermore, the sprite handles collision with background +;; elements (TODO), which is shared across all the scrolling examples. +;; +;; The sprite is stored in OAM memory $200-$20F, and the $30 and $31 memory +;; addresses are used for keeping up with the screen coordinates. +.scope Player + m_screen_x = $30 + m_screen_y = $31 + + .proc init + lda #40 + sta m_screen_x + sta m_screen_y + + lda #$01 + sta $201 + lda #$02 + sta $205 + lda #$11 + sta $209 + lda #$12 + sta $20D + + lda #0 + sta $202 + sta $206 + sta $20A + sta $20E + + rts + .endproc + + .proc update + jsr update_coordinates + jsr update_sprites + rts + .endproc + + .proc update_coordinates + lda #Joypad::BUTTON_UP + and Joypad::m_buttons1 + beq @check_down + dec m_screen_y + jmp @check_left + @check_down: + lda #Joypad::BUTTON_DOWN + and Joypad::m_buttons1 + beq @check_left + inc m_screen_y + @check_left: + lda #Joypad::BUTTON_LEFT + and Joypad::m_buttons1 + beq @check_right + dec m_screen_x + rts + @check_right: + lda #Joypad::BUTTON_RIGHT + and Joypad::m_buttons1 + beq @end + inc m_screen_x + ;; TODO: move scroll + @end: + rts + .endproc + + .proc update_sprites + lda m_screen_x + sta $203 + sta $20B + clc + adc #8 + sta $207 + sta $20F + + lda m_screen_y + sta $200 + sta $204 + clc + adc #8 + sta $208 + sta $20C + + rts + .endproc +.endscope diff --git a/scroll/include/ppu.s b/scroll/include/ppu.s new file mode 100644 index 0000000..23fd978 --- /dev/null +++ b/scroll/include/ppu.s @@ -0,0 +1,27 @@ +.segment "CODE" + +.scope PPU + CONTROL = $2000 + MASK = $2001 + STATUS = $2002 + SCROLL = $2005 + ADDRESS = $2006 + DATA = $2007 +.endscope + +.macro PPU_ADDR address + lda #.HIBYTE(address) + sta PPU::ADDRESS + lda #.LOBYTE(address) + sta PPU::ADDRESS +.endmacro + +;; WRITE_PPU_DATA is a macro that will write into PPU::ADDRESS the given address +;; and into PPU::DATA the given byte value. +.macro WRITE_PPU_DATA address, value + bit PPU::STATUS + + PPU_ADDR address + lda #value + sta PPU::DATA +.endmacro |
