diff --git a/mos-platform/nes/nesdoug/CMakeLists.txt b/mos-platform/nes/nesdoug/CMakeLists.txt index 6d4f4b483..9800f35df 100644 --- a/mos-platform/nes/nesdoug/CMakeLists.txt +++ b/mos-platform/nes/nesdoug/CMakeLists.txt @@ -5,9 +5,13 @@ install(FILES TYPE INCLUDE) add_platform_library(nes-nesdoug + metatile.c + metatile.s nesdoug.s nesdoug.c padlib.s + vram_buffer.c + vram_buffer.s zaplib.s ) target_include_directories(nes-nesdoug BEFORE PUBLIC ..) diff --git a/mos-platform/nes/nesdoug/metatile.c b/mos-platform/nes/nesdoug/metatile.c new file mode 100644 index 000000000..56cbffaf7 --- /dev/null +++ b/mos-platform/nes/nesdoug/metatile.c @@ -0,0 +1,15 @@ +// Copyright 2022 LLVM-MOS Project +// Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +// See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +// information. + +// Keeping these functions in C LTOs them in, which informs LTO code generation +// that the ZP regions aren't available. This saves users of the library from +// having to manually reserve ZP space from LTO. +__attribute__((section(".zp.meta_ptr"))) const char *META_PTR; +__attribute__((section(".zp.data_ptr"))) const char *DATA_PTR; + +void set_data_pointer(const void *data) { DATA_PTR = (const char *)data; } +void set_mt_pointer(const void *metatiles) { + META_PTR = (const char *)metatiles; +} diff --git a/mos-platform/nes/nesdoug/metatile.s b/mos-platform/nes/nesdoug/metatile.s new file mode 100644 index 000000000..6a6e3358d --- /dev/null +++ b/mos-platform/nes/nesdoug/metatile.s @@ -0,0 +1,270 @@ +;written by Doug Fraker +;version 1.2, 1/1/2022 + +.zeropage VRAM_BUF, META_PTR, DATA_PTR + + + +;void buffer_4_mt(int ppu_address, char index); +.section .text.buffer_4_mt,"ax",@progbits +.globl buffer_4_mt +buffer_4_mt: + sta __rc3 + lda __rc2 + ;a is the index into the data, get 4 metatiles + + and #$ee ;sanitize, x and y should be even + tay + lda (DATA_PTR), y + sta __rc6 + iny + lda (DATA_PTR), y + sta __rc7 + tya + clc + adc #15 + cmp #$f0 ;too far, data set only 240 bytes + bcs .Lskip + tay + lda (DATA_PTR), y + sta __rc8 + iny + lda (DATA_PTR), y + sta __rc9 +.Lskip: +;metatiles are in _rc6 - rc9 now + lda __rc3 + and #$9c ;sanitize, should be top left + sta __rc11 + stx __rc12 ;save for later, ppu_address + + sta __rc4 + txa + ora #$40 ;NT_UPD_HORZ + sta __rc5 + +;buffer the ppu_address + + lda #0 + sta __rc10 ;loop count, index to the metatiles + ldx VRAM_INDEX +.Lbuffer_4_mt_loop: + lda __rc4 ;low byte + sta VRAM_BUF+1, x + lda __rc5 ;high byte + sta VRAM_BUF,x + jsr .Lsub1 ;adds $20 to the address for next time + + lda #4 ;tell the system 4 bytes in a row + sta VRAM_BUF+2,x + sta VRAM_BUF+9,x ;loops twice, so, it does this twice + + jsr .Lsub2 ;gets y is which metatile + + lda (META_PTR), y + sta VRAM_BUF+3,x ; buffer the 4 tiles + iny + lda (META_PTR), y + sta VRAM_BUF+4,x + iny + lda (META_PTR), y + sta VRAM_BUF+10,x + iny + lda (META_PTR), y + sta VRAM_BUF+11,x + jsr .Lsub4 ;get attrib bits, shift into place + +;same, but for right side + lda __rc4 ;low byte ppu address, again + sta VRAM_BUF+8,x + lda __rc5 ;high byte + sta VRAM_BUF+7,x + jsr .Lsub1 + + inc __rc10 ;count and index + jsr .Lsub2 + lda (META_PTR), y + sta VRAM_BUF+5,x ; buffer the 4 tiles + iny + lda (META_PTR), y + sta VRAM_BUF+6,x + iny + lda (META_PTR), y + sta VRAM_BUF+12,x + iny + lda (META_PTR), y + sta VRAM_BUF+13,x + jsr .Lsub4 + + txa ;adjust the vram index to the next set + clc + adc #14 + tax + + jsr .Lsub3 ;check if lowest y on screen, skip the la + bne .Lloop_done + + inc __rc10 + ldy __rc10 + cpy #4 + bcc .Lbuffer_4_mt_loop + +.Lloop_done: + + + +;now push 1 attribute byte to the vram buffer +;first, shift the bits to get an attribute address +;we stored the original at TEMP+7,8, 8 is high byte +;a bunch of bit shifting to get 3 bits from x and 3 y + lsr __rc12 ;high byte + ror __rc11 + lsr __rc12 + ror __rc11 + lda __rc11 + pha ;save + and #7 ;just the x bits + sta __rc4 + pla + lsr a ;just the y bits + lsr a + and #$f8 + ora #$c0 + ora __rc4 + sta __rc4 ;low byte +;now high byte + lda __rc12 + asl a + asl a + ora #$23 + sta __rc5 ;high byte, and the low byte is in TEMP + + +;finally, push it all to the vram_buffer as a single byte + lda __rc5 ;high byte + sta VRAM_BUF,x + inx + lda __rc4 ;low byte + sta VRAM_BUF,x + inx + lda __rc14 + sta VRAM_BUF,x + inx + lda #$ff ;=NT_UPD_EOF + sta VRAM_BUF,x + stx VRAM_INDEX + rts + + +.Lsub1: ;add $20 is a 1 down on the screen + tay ;high byte + lda __rc4 + clc + adc #$20 + sta __rc4 + bcc .Lsub1b + iny +.Lsub1b: + sty __rc5 + rts + + +.Lsub2: ;get the next metatile offset + ldy __rc10 + lda __rc6, y ;metatile +;multiply by 5 + sta __rc13 + asl a + asl a ;x4 = 4 bytes per + clc + adc __rc13 + tay + rts + + +.Lsub3: ;check make sure we're not at the lowest y and overflowing + ldy #0 ;x is forbidden + lda __rc12 ;high byte + and #$03 + cmp #$03 + bne .Lnot_overflow + lda __rc11 + cmp #$80 ;last row of mt + bcc .Lnot_overflow + iny + lsr __rc14 ;make sure the attrib bits in correct position + lsr __rc14 + lsr __rc14 + lsr __rc14 +.Lnot_overflow: + tya ;set flag + rts + + +.Lsub4: ;get attrib bits, roll them in place + iny + lda (META_PTR), y ;5th byte = attribute + and #3 ;just need 2 bits + ror a ;bit to carry + ror __rc14 ;shift carry in + ror a ;bit to carry + ror __rc14 ;roll the a.t. bits in the high 2 bits + rts + + + + +;void buffer_1_mt(int ppu_address, char metatile); +.section .text.buffer_1_mt,"ax",@progbits +.globl buffer_1_mt +buffer_1_mt: + and #$de ;sanitize, should be even x and y + sta __rc4 + txa + ora #$40 ;NT_UPD_HORZ + sta __rc5 + + ldx VRAM_INDEX + lda __rc4 ;ppu address + sta VRAM_BUF+1,x + clc + adc #$20 ;shouldn't be rollover + sta VRAM_BUF+6,x + + lda __rc5 + sta VRAM_BUF,x + sta VRAM_BUF+5,x + + lda #2 ;tell the system 2 bytes in a row + sta VRAM_BUF+2,x + sta VRAM_BUF+7,x + + lda __rc2 ;which metatile + asl a + asl a + clc + adc __rc2 ;multiply 5 + tay + lda (META_PTR), y ;tile + sta VRAM_BUF+3,x + iny + lda (META_PTR), y ;tile + sta VRAM_BUF+4,x + iny + lda (META_PTR), y ;tile + sta VRAM_BUF+8,x + iny + lda (META_PTR), y ;tile + sta VRAM_BUF+9,x + + txa + clc + adc #10 + sta VRAM_INDEX + tax + lda #$ff ;=NT_UPD_EOF + sta VRAM_BUF,x + rts + + + diff --git a/mos-platform/nes/nesdoug/nesdoug.c b/mos-platform/nes/nesdoug/nesdoug.c index 88b638a79..50147bec6 100644 --- a/mos-platform/nes/nesdoug/nesdoug.c +++ b/mos-platform/nes/nesdoug/nesdoug.c @@ -7,21 +7,6 @@ // based on code by Groepaz/Hitmen , Ullrich von Bassewitz // -// Keeping these functions in C LTOs them in, which informs LTO code generation -// that the ZP regions aren't available. This saves users of the library from -// having to manually reserve ZP space from LTO. -__attribute__((section(".zp.vram_index"))) char VRAM_INDEX; -__attribute__((section(".zp.meta_ptr"))) const char *META_PTR; -__attribute__((section(".zp.data_ptr"))) const char *DATA_PTR; - -extern char VRAM_BUF[]; -void set_vram_update(const void *buf); -void set_vram_buffer(void) { - VRAM_BUF[0] = 0xff; - VRAM_INDEX = 0; - set_vram_update(VRAM_BUF); -} - extern char PAD_STATET[]; char get_pad_new(char pad) { return PAD_STATET[pad]; } @@ -44,11 +29,6 @@ void set_scroll_y(unsigned y) { PPUCTRL_VAR = PPUCTRL_VAR & 0xfd | (y >> 8 & 0x01) << 1; } -void set_data_pointer(const void *data) { DATA_PTR = (const char *)data; } -void set_mt_pointer(const void *metatiles) { - META_PTR = (const char *)metatiles; -} - extern volatile char PPUMASK_VAR; void color_emphasis(char color) { PPUMASK_VAR = PPUMASK_VAR & 0x1f | color & 0xe0; diff --git a/mos-platform/nes/nesdoug/nesdoug.s b/mos-platform/nes/nesdoug/nesdoug.s index 66876ce8a..a98cee8eb 100644 --- a/mos-platform/nes/nesdoug/nesdoug.s +++ b/mos-platform/nes/nesdoug/nesdoug.s @@ -5,125 +5,6 @@ .include "nes.inc" .include "neslib.inc" -.zeropage VRAM_INDEX, META_PTR, DATA_PTR - -.section .noinit.vram_buf,"aw",@nobits -.globl VRAM_BUF -.balign 128 -VRAM_BUF: - .zero 128 - -.text -.global __post_vram_update -__post_vram_update: - ldx #$ff - stx VRAM_BUF - inx ;x=0 - stx VRAM_INDEX - rts - -;void multi_vram_buffer_horz(char * data, char len, int ppu_address); -.section .text.multi_vram_buffer_horz,"ax",@progbits -.globl multi_vram_buffer_horz -multi_vram_buffer_horz: - ; A - len - ; X - data - ; __rc4 - >ppu_address - ldy VRAM_INDEX - - sta __rc5 ; save len for loop comparison - sta VRAM_BUF+2, y ; store len in header - - lda #$40 ; load horizontal flag - -multi_vram_buffer_common: - ora __rc4 ; combine direction flag with upper address byte - sta VRAM_BUF+0, y ; store upper byte in header - txa - sta VRAM_BUF+1, y ; store lower byte in header - - ; get data index past header - tya - clc - adc #3 - tax ;need y for source, x is for dest and for vram_index - - ldy #0 - - ; TODO: unroll? -.Lmulti_vram_buffer_common_loop: - lda (__rc2), y - sta VRAM_BUF, x - inx - iny - cpy __rc5 - bne .Lmulti_vram_buffer_common_loop - lda #$ff ;=NT_UPD_EOF - sta VRAM_BUF, x - stx VRAM_INDEX - rts - - - - -;void multi_vram_buffer_vert(char * data, char len, int ppu_address); -.section .text.multi_vram_buffer_vert,"ax",@progbits -.globl multi_vram_buffer_vert -multi_vram_buffer_vert: - ; A - len - ; X - data - ; __rc4 - >ppu_address - ldy VRAM_INDEX - - sta __rc5 ; save len for loop comparison - sta VRAM_BUF+2, y ; store len in header - - lda #$80 ; load vertical flag - bne multi_vram_buffer_common ; always taken - - - - -;void one_vram_buffer(char data, int ppu_address); -.section .text.one_vram_buffer,"ax",@progbits -.globl one_vram_buffer -one_vram_buffer: - ; A - data - ; X - ppu_address - ldy VRAM_INDEX - - sta VRAM_BUF+2, y ; data - lda __rc2 - sta VRAM_BUF, y ; address hi - txa - sta VRAM_BUF+1, y ; adderess lo - iny - iny - iny - lda #$ff ;=NT_UPD_EOF - sta VRAM_BUF, y - sty VRAM_INDEX - rts - - - - -;void clear_vram_buffer(void); -;_clear_vram_buffer: -; lda #0 -; sta VRAM_INDEX -; lda #$ff -; sta VRAM_BUF -; rts - - - - ;char check_collision(void * object1, void * object2); .section .text.check_collision,"ax",@progbits .globl check_collision @@ -370,270 +251,6 @@ get_at_addr: -;void buffer_4_mt(int ppu_address, char index); -.section .text.buffer_4_mt,"ax",@progbits -.globl buffer_4_mt -buffer_4_mt: - sta __rc3 - lda __rc2 - ;a is the index into the data, get 4 metatiles - - and #$ee ;sanitize, x and y should be even - tay - lda (DATA_PTR), y - sta __rc6 - iny - lda (DATA_PTR), y - sta __rc7 - tya - clc - adc #15 - cmp #$f0 ;too far, data set only 240 bytes - bcs .Lskip - tay - lda (DATA_PTR), y - sta __rc8 - iny - lda (DATA_PTR), y - sta __rc9 -.Lskip: -;metatiles are in _rc6 - rc9 now - lda __rc3 - and #$9c ;sanitize, should be top left - sta __rc11 - stx __rc12 ;save for later, ppu_address - - sta __rc4 - txa - ora #$40 ;NT_UPD_HORZ - sta __rc5 - -;buffer the ppu_address - - lda #0 - sta __rc10 ;loop count, index to the metatiles - ldx VRAM_INDEX -.Lbuffer_4_mt_loop: - lda __rc4 ;low byte - sta VRAM_BUF+1, x - lda __rc5 ;high byte - sta VRAM_BUF,x - jsr .Lsub1 ;adds $20 to the address for next time - - lda #4 ;tell the system 4 bytes in a row - sta VRAM_BUF+2,x - sta VRAM_BUF+9,x ;loops twice, so, it does this twice - - jsr .Lsub2 ;gets y is which metatile - - lda (META_PTR), y - sta VRAM_BUF+3,x ; buffer the 4 tiles - iny - lda (META_PTR), y - sta VRAM_BUF+4,x - iny - lda (META_PTR), y - sta VRAM_BUF+10,x - iny - lda (META_PTR), y - sta VRAM_BUF+11,x - jsr .Lsub4 ;get attrib bits, shift into place - -;same, but for right side - lda __rc4 ;low byte ppu address, again - sta VRAM_BUF+8,x - lda __rc5 ;high byte - sta VRAM_BUF+7,x - jsr .Lsub1 - - inc __rc10 ;count and index - jsr .Lsub2 - lda (META_PTR), y - sta VRAM_BUF+5,x ; buffer the 4 tiles - iny - lda (META_PTR), y - sta VRAM_BUF+6,x - iny - lda (META_PTR), y - sta VRAM_BUF+12,x - iny - lda (META_PTR), y - sta VRAM_BUF+13,x - jsr .Lsub4 - - txa ;adjust the vram index to the next set - clc - adc #14 - tax - - jsr .Lsub3 ;check if lowest y on screen, skip the la - bne .Lloop_done - - inc __rc10 - ldy __rc10 - cpy #4 - bcc .Lbuffer_4_mt_loop - -.Lloop_done: - - - -;now push 1 attribute byte to the vram buffer -;first, shift the bits to get an attribute address -;we stored the original at TEMP+7,8, 8 is high byte -;a bunch of bit shifting to get 3 bits from x and 3 y - lsr __rc12 ;high byte - ror __rc11 - lsr __rc12 - ror __rc11 - lda __rc11 - pha ;save - and #7 ;just the x bits - sta __rc4 - pla - lsr a ;just the y bits - lsr a - and #$f8 - ora #$c0 - ora __rc4 - sta __rc4 ;low byte -;now high byte - lda __rc12 - asl a - asl a - ora #$23 - sta __rc5 ;high byte, and the low byte is in TEMP - - -;finally, push it all to the vram_buffer as a single byte - lda __rc5 ;high byte - sta VRAM_BUF,x - inx - lda __rc4 ;low byte - sta VRAM_BUF,x - inx - lda __rc14 - sta VRAM_BUF,x - inx - lda #$ff ;=NT_UPD_EOF - sta VRAM_BUF,x - stx VRAM_INDEX - rts - - -.Lsub1: ;add $20 is a 1 down on the screen - tay ;high byte - lda __rc4 - clc - adc #$20 - sta __rc4 - bcc .Lsub1b - iny -.Lsub1b: - sty __rc5 - rts - - -.Lsub2: ;get the next metatile offset - ldy __rc10 - lda __rc6, y ;metatile -;multiply by 5 - sta __rc13 - asl a - asl a ;x4 = 4 bytes per - clc - adc __rc13 - tay - rts - - -.Lsub3: ;check make sure we're not at the lowest y and overflowing - ldy #0 ;x is forbidden - lda __rc12 ;high byte - and #$03 - cmp #$03 - bne .Lnot_overflow - lda __rc11 - cmp #$80 ;last row of mt - bcc .Lnot_overflow - iny - lsr __rc14 ;make sure the attrib bits in correct position - lsr __rc14 - lsr __rc14 - lsr __rc14 -.Lnot_overflow: - tya ;set flag - rts - - -.Lsub4: ;get attrib bits, roll them in place - iny - lda (META_PTR), y ;5th byte = attribute - and #3 ;just need 2 bits - ror a ;bit to carry - ror __rc14 ;shift carry in - ror a ;bit to carry - ror __rc14 ;roll the a.t. bits in the high 2 bits - rts - - - - -;void buffer_1_mt(int ppu_address, char metatile); -.section .text.buffer_1_mt,"ax",@progbits -.globl buffer_1_mt -buffer_1_mt: - and #$de ;sanitize, should be even x and y - sta __rc4 - txa - ora #$40 ;NT_UPD_HORZ - sta __rc5 - - ldx VRAM_INDEX - lda __rc4 ;ppu address - sta VRAM_BUF+1,x - clc - adc #$20 ;shouldn't be rollover - sta VRAM_BUF+6,x - - lda __rc5 - sta VRAM_BUF,x - sta VRAM_BUF+5,x - - lda #2 ;tell the system 2 bytes in a row - sta VRAM_BUF+2,x - sta VRAM_BUF+7,x - - lda __rc2 ;which metatile - asl a - asl a - clc - adc __rc2 ;multiply 5 - tay - lda (META_PTR), y ;tile - sta VRAM_BUF+3,x - iny - lda (META_PTR), y ;tile - sta VRAM_BUF+4,x - iny - lda (META_PTR), y ;tile - sta VRAM_BUF+8,x - iny - lda (META_PTR), y ;tile - sta VRAM_BUF+9,x - - txa - clc - adc #10 - sta VRAM_INDEX - tax - lda #$ff ;=NT_UPD_EOF - sta VRAM_BUF,x - rts - - - - ;void xy_split(unsigned x, unsigned y); .section .text.xy_split,"ax",@progbits .globl xy_split diff --git a/mos-platform/nes/nesdoug/vram_buffer.c b/mos-platform/nes/nesdoug/vram_buffer.c new file mode 100644 index 000000000..8f46ce41f --- /dev/null +++ b/mos-platform/nes/nesdoug/vram_buffer.c @@ -0,0 +1,13 @@ +// written by Doug Fraker +// version 1.2, 1/1/2022 + +__attribute__((section(".zp.vram_index"))) char VRAM_INDEX; + +extern char VRAM_BUF[]; + +void set_vram_update(const void *buf); +void set_vram_buffer(void) { + VRAM_BUF[0] = 0xff; + VRAM_INDEX = 0; + set_vram_update(VRAM_BUF); +} diff --git a/mos-platform/nes/nesdoug/vram_buffer.s b/mos-platform/nes/nesdoug/vram_buffer.s new file mode 100644 index 000000000..5115fc1d9 --- /dev/null +++ b/mos-platform/nes/nesdoug/vram_buffer.s @@ -0,0 +1,118 @@ +;written by Doug Fraker +;version 1.2, 1/1/2022 + +.zeropage VRAM_INDEX + +.section .noinit.vram_buf,"aw",@nobits +.globl VRAM_BUF +.balign 128 +VRAM_BUF: + .zero 128 + +.text +.global __post_vram_update +__post_vram_update: + ldx #$ff + stx VRAM_BUF + inx ;x=0 + stx VRAM_INDEX + rts + +;void multi_vram_buffer_horz(char * data, char len, int ppu_address); +.section .text.multi_vram_buffer_horz,"ax",@progbits +.globl multi_vram_buffer_horz +multi_vram_buffer_horz: + ; A - len + ; X - data + ; __rc4 - >ppu_address + ldy VRAM_INDEX + + sta __rc5 ; save len for loop comparison + sta VRAM_BUF+2, y ; store len in header + + lda #$40 ; load horizontal flag + +multi_vram_buffer_common: + ora __rc4 ; combine direction flag with upper address byte + sta VRAM_BUF+0, y ; store upper byte in header + txa + sta VRAM_BUF+1, y ; store lower byte in header + + ; get data index past header + tya + clc + adc #3 + tax ;need y for source, x is for dest and for vram_index + + ldy #0 + + ; TODO: unroll? +.Lmulti_vram_buffer_common_loop: + lda (__rc2), y + sta VRAM_BUF, x + inx + iny + cpy __rc5 + bne .Lmulti_vram_buffer_common_loop + lda #$ff ;=NT_UPD_EOF + sta VRAM_BUF, x + stx VRAM_INDEX + rts + + + + +;void multi_vram_buffer_vert(char * data, char len, int ppu_address); +.section .text.multi_vram_buffer_vert,"ax",@progbits +.globl multi_vram_buffer_vert +multi_vram_buffer_vert: + ; A - len + ; X - data + ; __rc4 - >ppu_address + ldy VRAM_INDEX + + sta __rc5 ; save len for loop comparison + sta VRAM_BUF+2, y ; store len in header + + lda #$80 ; load vertical flag + bne multi_vram_buffer_common ; always taken + + + + +;void one_vram_buffer(char data, int ppu_address); +.section .text.one_vram_buffer,"ax",@progbits +.globl one_vram_buffer +one_vram_buffer: + ; A - data + ; X - ppu_address + ldy VRAM_INDEX + + sta VRAM_BUF+2, y ; data + lda __rc2 + sta VRAM_BUF, y ; address hi + txa + sta VRAM_BUF+1, y ; adderess lo + iny + iny + iny + lda #$ff ;=NT_UPD_EOF + sta VRAM_BUF, y + sty VRAM_INDEX + rts + + + + +;void clear_vram_buffer(void); +;_clear_vram_buffer: +; lda #0 +; sta VRAM_INDEX +; lda #$ff +; sta VRAM_BUF +; rts diff --git a/mos-platform/nes/neslib/CMakeLists.txt b/mos-platform/nes/neslib/CMakeLists.txt index b5bd9c94b..b599d4419 100644 --- a/mos-platform/nes/neslib/CMakeLists.txt +++ b/mos-platform/nes/neslib/CMakeLists.txt @@ -8,7 +8,15 @@ add_platform_library(nes-neslib neslib.s ntsc.c ntsc.s + oam_update.c + oam_update.s + pal_bright.c + pal_bright.s + pal_update.c + pal_update.s rand.c - rand.s) + rand.s + vram_update.c + vram_update.s) target_include_directories(nes-neslib BEFORE PUBLIC ..) target_link_libraries(nes-neslib PRIVATE common-asminc nes-neslib-asminc) diff --git a/mos-platform/nes/neslib/neslib.c b/mos-platform/nes/neslib/neslib.c index 25d6afff8..e72b9e0f6 100644 --- a/mos-platform/nes/neslib/neslib.c +++ b/mos-platform/nes/neslib/neslib.c @@ -16,11 +16,6 @@ __attribute__((section(".zp.frame_cnt1"))) volatile char FRAME_CNT1; __attribute__((section(".zp.frame_cnt2"))) volatile char FRAME_CNT2; __attribute__((section(".zp.vram_update"))) volatile char VRAM_UPDATE; -__attribute__((section(".zp.name_upd_adr"))) volatile const char *NAME_UPD_ADR; -__attribute__((section(".zp.name_upd_enable"))) volatile char NAME_UPD_ENABLE; -__attribute__((section(".zp.pal_update"))) volatile char PAL_UPDATE; -__attribute__((section(".zp.pal_bg_ptr"))) volatile const char *PAL_BG_PTR; -__attribute__((section(".zp.pal_spr_ptr"))) volatile const char *PAL_SPR_PTR; __attribute__((section(".zp.scroll_x"))) volatile char SCROLL_X; __attribute__((section(".zp.scroll_y"))) volatile char SCROLL_Y; __attribute__((section(".zp.scroll_x1"))) volatile char SCROLL_X1; @@ -31,30 +26,6 @@ __attribute__((section(".zp.pad_statet"))) char PAD_STATET[2]; __attribute__((section(".zp.ppu_ctrl_var"))) volatile char PPUCTRL_VAR; __attribute__((section(".zp.ppu_ctrl_var1"))) volatile char PPUCTRL_VAR1; __attribute__((section(".zp.ppu_mask_var"))) volatile char PPUMASK_VAR; -__attribute__((section(".zp.sprid"))) unsigned SPRID; - -extern volatile char PAL_BUF[]; -void pal_col(char index, char color) { - PAL_BUF[index & 0x1f] = color; - ++PAL_UPDATE; -} - -extern const char __palBrightTableL[]; -extern const char __palBrightTableH[]; -void pal_spr_bright(char bright) { - PAL_SPR_PTR = (const char *)(__palBrightTableH[bright] << 8 | - __palBrightTableL[bright]); - PAL_UPDATE = 1; -} -void pal_bg_bright(char bright) { - PAL_BG_PTR = (const char *)(__palBrightTableH[bright] << 8 | - __palBrightTableL[bright]); - PAL_UPDATE = 1; -} -void pal_bright(char bright) { - pal_spr_bright(bright); - pal_bg_bright(bright); -} void ppu_wait_nmi(void); void ppu_off(void) { @@ -78,10 +49,6 @@ void ppu_on_spr(void) { void ppu_mask(char mask) { PPUMASK_VAR = mask; } -void oam_set(char index) { SPRID = index & 0xfc; } - -char oam_get(void) { return SPRID; } - char pad_poll(char pad); char pad_trigger(char pad) { pad_poll(pad); @@ -90,11 +57,6 @@ char pad_trigger(char pad) { char pad_state(char pad) { return PAD_STATE[pad]; } -void set_vram_update(const void *buf) { - NAME_UPD_ADR = buf; - NAME_UPD_ENABLE = NAME_UPD_ADR != 0; -} - void vram_adr(unsigned adr) { PPU.vram.address = adr >> 8; PPU.vram.address = adr & 0xff; diff --git a/mos-platform/nes/neslib/neslib.inc b/mos-platform/nes/neslib/neslib.inc index ae2e40c0f..a6592d514 100644 --- a/mos-platform/nes/neslib/neslib.inc +++ b/mos-platform/nes/neslib/neslib.inc @@ -1,4 +1,4 @@ -.zeropage FRAME_CNT1, FRAME_CNT2, VRAM_UPDATE, NAME_UPD_ADR, NAME_UPD_ENABLE -.zeropage PAL_UPDATE, PAL_BG_PTR, PAL_SPR_PTR, SCROLL_X, SCROLL_Y, SCROLL_X1 +.zeropage FRAME_CNT1, FRAME_CNT2, VRAM_UPDATE +.zeropage SCROLL_X, SCROLL_Y, SCROLL_X1 .zeropage SCROLL_Y1, PAD_STATE, PAD_STATEP, PAD_STATET, PPUCTRL_VAR -.zeropage PPUCTRL_VAR1, PPUMASK_VAR, SPRID +.zeropage PPUCTRL_VAR1, PPUMASK_VAR diff --git a/mos-platform/nes/neslib/neslib.s b/mos-platform/nes/neslib/neslib.s index 01592f37d..731638548 100644 --- a/mos-platform/nes/neslib/neslib.s +++ b/mos-platform/nes/neslib/neslib.s @@ -16,17 +16,6 @@ .include "neslib.inc" .include "ntsc.inc" -; Reserve space at beginning of RAM for OAM buffer. -.section .noinit.oam_buf,"a",@nobits -.globl OAM_BUF -.align 256 -OAM_BUF: - .space 256 - -; Place the pallette buffer at the very bottom 32 bytes of the hard stack. -.globl PAL_BUF -PAL_BUF = 0x0100 - .section .init.100,"axR",@progbits clearRAM: lda #0 @@ -44,7 +33,7 @@ clearRAM: bne 1b -.section .init.270,"axR",@progbits +.section .init.255,"axR",@progbits clearPalette: lda #$3f sta PPUADDR @@ -69,95 +58,37 @@ clearVRAM: dey bne 1b - lda #4 - jsr pal_bright - jsr pal_clear - jsr oam_clear - - lda #0b10000000 - sta PPUCTRL_VAR - sta PPUCTRL ;enable NMI - lda #0b00000110 - sta PPUMASK_VAR +.section .init.400,"axR",@progbits +.globl neslib_final_init +neslib_final_init: lda #0 sta PPUSCROLL sta PPUSCROLL -.section .nmi.050,"axR",@progbits - jsr neslib_nmi -.section .text.neslib_nmi,"ax",@progbits -.globl neslib_nmi -neslib_nmi: +.section .nmi.050,"axR",@progbits +.globl neslib_nmi_begin +neslib_nmi_begin: lda PPUMASK_VAR ;if rendering is disabled, do not access the VRAM at all and #0b00011000 bne .LrenderingOn - jmp .LskipAll + jmp neslib_nmi_skip .LrenderingOn: lda VRAM_UPDATE ;is the frame complete? bne .LdoUpdate - jmp .LskipAll ;skipUpd + jmp neslib_nmi_skip .LdoUpdate: lda #0 sta VRAM_UPDATE - lda #>OAM_BUF ;update OAM - sta OAMDMA - - lda PAL_UPDATE ;update palette if needed - bne .LupdPal - jmp .LupdVRAM - -.LupdPal: - - ldx #0 - stx PAL_UPDATE - - lda #$3f - sta PPUADDR - stx PPUADDR - - ldy PAL_BUF ;background color, remember it in X - lda (PAL_BG_PTR),y - sta PPUDATA - tax - - .irp i,0,1,2 - ldy PAL_BUF+1+\i - lda (PAL_BG_PTR),y - sta PPUDATA - .endr - - .irp j,0,1,2 - stx PPUDATA ;background color - .irp i,0,1,2 - ldy PAL_BUF+5+(\j*4)+\i - lda (PAL_BG_PTR),y - sta PPUDATA - .endr - .endr - - .irp j,0,1,2,3 - stx PPUDATA ;background color - .irp i,0,1,2 - ldy PAL_BUF+17+(\j*4)+\i - lda (PAL_SPR_PTR),y - sta PPUDATA - .endr - .endr - -.LupdVRAM: - lda NAME_UPD_ENABLE - beq .LskipUpd - - jsr flush_vram_update2 - -.LskipUpd: +.section .nmi.075,"axR",@progbits +.globl neslib_nmi_end +neslib_nmi_end: lda #0 sta PPUADDR sta PPUADDR @@ -170,8 +101,7 @@ neslib_nmi: lda PPUCTRL_VAR sta PPUCTRL -.LskipAll: - +neslib_nmi_skip: lda PPUMASK_VAR sta PPUMASK @@ -183,203 +113,6 @@ neslib_nmi: lda #0 sta FRAME_CNT2 .LskipNtsc: - rts - -;void pal_all(const char *data); -.section .text.pal_all,"ax",@progbits -.global pal_all -pal_all: - - ldx #$00 - lda #$20 - -.Lpal_copy: - - sta __rc4 - - ldy #$00 - -0: - - lda (__rc2),y - sta PAL_BUF,x - inx - iny - dec __rc4 - bne 0b - - inc PAL_UPDATE - - rts - - - -;void pal_bg(const char *data); -.section .text.pal_bg,"ax",@progbits -.globl pal_bg -pal_bg: - - ldx #$00 - lda #$10 - jmp .Lpal_copy - - - -;void pal_spr(const char *data); -.section .text.pal_spr,"ax",@progbits -.globl pal_spr -pal_spr: - - ldx #$10 - txa - jmp .Lpal_copy - - - -;void pal_clear(void); -.section .text.pal_clear,"ax",@progbits -.globl pal_clear -pal_clear: - - lda #$0f - ldx #0 - -0: - - sta PAL_BUF,x - inx - cpx #$20 - bne 0b - stx PAL_UPDATE - rts - - - -;void oam_clear(void); -.section .text.oam_clear,"ax",@progbits -.globl oam_clear -oam_clear: - - ldx #0 - stx SPRID ; automatically sets sprid to zero - lda #$ff -0: - sta OAM_BUF,x - inx - inx - inx - inx - bne 0b - rts - - -;void oam_size(unsigned char size); -.section .text.oam_size,"ax",@progbits -.globl oam_size -oam_size: - - asl a - asl a - asl a - asl a - asl a - and #$20 - sta __rc2 - lda PPUCTRL_VAR - and #$df - ora __rc2 - sta PPUCTRL_VAR - - rts - - - -;void oam_spr(unsigned char x,unsigned char y,unsigned char chrnum,unsigned char attr); -;sprid removed -.section .text.oam_spr,"ax",@progbits -.globl oam_spr -oam_spr: - ldy SPRID - sta OAM_BUF+3,y - - txa - sta OAM_BUF+0,y - - lda __rc2 - sta OAM_BUF+1,y - - lda __rc3 - sta OAM_BUF+2,y - - tya - clc ; if we can prove Carry is always false, then we don't need this - adc #$04 - sta SPRID - rts - - - -;void oam_meta_spr(unsigned char x,unsigned char y,const unsigned char *data); -;sprid removed -.section .text.oam_meta_spr,"ax",@progbits -.globl oam_meta_spr -oam_meta_spr: - - sta __rc4 - stx __rc5 - ldx SPRID - ldy #0 -1: - lda (__rc2),y ;x offset - cmp #$80 - beq 2f - iny - clc - adc __rc4 - sta OAM_BUF+3,x - lda (__rc2),y ;y offset - iny - clc - adc __rc5 - sta OAM_BUF+0,x - lda (__rc2),y ;tile - iny - sta OAM_BUF+1,x - lda (__rc2),y ;attribute - iny - sta OAM_BUF+2,x - inx - inx - inx - inx - jmp 1b -2: - stx SPRID - rts - - - -;void oam_hide_rest(void); -;sprid removed -.section .text.oam_hide_rest,"ax",@progbits -.globl oam_hide_rest -oam_hide_rest: - - ldx SPRID - lda #240 - -0: - - sta OAM_BUF,x - inx - inx - inx - inx - bne 0b - ;x is zero - stx SPRID - rts - ;void ppu_wait_frame(void); @@ -709,94 +442,6 @@ pad_poll: -;void flush_vram_update(unsigned char *buf); -.section .text.flush_vram_update,"ax",@progbits -.globl flush_vram_update -flush_vram_update: - lda __rc2 - sta NAME_UPD_ADR+0 - lda __rc3 - sta NAME_UPD_ADR+1 - -.globl flush_vram_update2 -flush_vram_update2: ;minor changes % - - ldy #0 - -.LupdName: - ; First byte is upper PPU address or #$ff if done - lda (NAME_UPD_ADR),y - iny - cmp #$40 ; bits 6 and 7 indicate sequential ops - bcc .LupdSingle - - ; save upper address byte for arithmetic - tax - lda PPUCTRL_VAR - cpx #$80 ; below 80 is horizontal - bmi .LupdHorzSeq - cpx #$ff - beq .LupdDone - -.LupdVertSeq: - ; Set control bit for vertical traversal - ora #$04 ; TODO constants for ctrl flags? - bne .LupdNameSeq ;always taken - -.LupdSingle: - sta PPUADDR - lda (NAME_UPD_ADR),y ; address lo - iny - sta PPUADDR - lda (NAME_UPD_ADR),y ; data - iny - sta PPUDATA - bne .LupdName ; always taken. Assumes index never wraps - -.LupdHorzSeq: - ; Clear control bit for vertical traversal - and #$fb - -.LupdNameSeq: - ; Store new control value - sta PPUCTRL - - ; Mask out top 2 bits of upper address byte - txa - and #$3F - - sta PPUADDR - lda (NAME_UPD_ADR),y ; address lo - iny - sta PPUADDR - lda (NAME_UPD_ADR),y ; size - iny - - ; store size in counter - tax - -.LupdNameLoop: - - lda (NAME_UPD_ADR),y - iny - sta PPUDATA - dex - bne .LupdNameLoop - - lda PPUCTRL_VAR - sta PPUCTRL - - jmp .LupdName - -.LupdDone: - jmp __post_vram_update - -.weak __post_vram_update -__post_vram_update: - rts - - - ;void vram_fill(unsigned char n,unsigned int len); .section .text.vram_fill,"ax",@progbits .globl vram_fill @@ -854,40 +499,3 @@ vram_inc: rts - -.section .rodata.bright_table,"a",@progbits -.globl __palBrightTableL -.globl __palBrightTableH -__palBrightTableL: - - .byte palBrightTable0@mos16lo,palBrightTable1@mos16lo,palBrightTable2@mos16lo - .byte palBrightTable3@mos16lo,palBrightTable4@mos16lo,palBrightTable5@mos16lo - .byte palBrightTable6@mos16lo,palBrightTable7@mos16lo,palBrightTable8@mos16lo - -__palBrightTableH: - - .byte palBrightTable0@mos16hi,palBrightTable1@mos16hi,palBrightTable2@mos16hi - .byte palBrightTable3@mos16hi,palBrightTable4@mos16hi,palBrightTable5@mos16hi - .byte palBrightTable6@mos16hi,palBrightTable7@mos16hi,palBrightTable8@mos16hi - -palBrightTable0: - .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f ;black -palBrightTable1: - .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f -palBrightTable2: - .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f -palBrightTable3: - .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f -palBrightTable4: - .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0f,$0f,$0f ;normal colors -palBrightTable5: - .byte $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1a,$1b,$1c,$00,$00,$00 -palBrightTable6: - .byte $10,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$10,$10,$10 ;$10 because $20 is the same as $30 -palBrightTable7: - .byte $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$20,$20,$20 -palBrightTable8: - .byte $30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30 ;white - .byte $30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30 - .byte $30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30 - .byte $30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30 diff --git a/mos-platform/nes/neslib/ntsc.s b/mos-platform/nes/neslib/ntsc.s index c4780a529..893b8fa45 100644 --- a/mos-platform/nes/neslib/ntsc.s +++ b/mos-platform/nes/neslib/ntsc.s @@ -6,6 +6,12 @@ .section .init.275,"axR",@progbits .globl __do_init_ntsc_mode __do_init_ntsc_mode: + lda #0b10000000 + sta PPUCTRL_VAR + sta PPUCTRL ;enable NMI + lda #0b00000110 + sta PPUMASK_VAR + waitSync3: lda FRAME_CNT1 1: @@ -27,12 +33,3 @@ detectNTSC: jsr ppu_off - lda #0 - sta __rc2 - sta __rc3 - jsr set_vram_update - - lda #0 - sta PPUSCROLL - sta PPUSCROLL - diff --git a/mos-platform/nes/neslib/oam_update.c b/mos-platform/nes/neslib/oam_update.c new file mode 100644 index 000000000..18e02036a --- /dev/null +++ b/mos-platform/nes/neslib/oam_update.c @@ -0,0 +1,10 @@ +// Copyright 2023 LLVM-MOS Project +// Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +// See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +// information. + +__attribute__((section(".zp.sprid"))) unsigned SPRID; + +void oam_set(char index) { SPRID = index & 0xfc; } + +char oam_get(void) { return SPRID; } diff --git a/mos-platform/nes/neslib/oam_update.s b/mos-platform/nes/neslib/oam_update.s new file mode 100644 index 000000000..55709445f --- /dev/null +++ b/mos-platform/nes/neslib/oam_update.s @@ -0,0 +1,135 @@ +; Copyright 2023 LLVM-MOS Project +; Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +; See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +; information. + +.zeropage SPRID + +.include "nes.inc" + +; Reserve space at beginning of RAM for OAM buffer. +.section .noinit.oam_buf,"a",@nobits +.globl OAM_BUF +.align 256 +OAM_BUF: + .space 256 + + +.section .init.270,"axR",@progbits +.globl oam_update_init +oam_update_init: + jsr oam_clear + + +.section .nmi.055,"axR",@progbits +.globl oam_update_nmi +oam_update_nmi: + lda #>OAM_BUF + sta OAMDMA + + + +;void oam_clear(void); +.section .text.oam_clear,"ax",@progbits +.globl oam_clear +oam_clear: + + ldx #0 + stx SPRID ; automatically sets sprid to zero + lda #$ff +0: + sta OAM_BUF,x + inx + inx + inx + inx + bne 0b + rts + + + +;void oam_spr(unsigned char x,unsigned char y,unsigned char chrnum,unsigned char attr); +;sprid removed +.section .text.oam_spr,"ax",@progbits +.globl oam_spr +oam_spr: + ldy SPRID + sta OAM_BUF+3,y + + txa + sta OAM_BUF+0,y + + lda __rc2 + sta OAM_BUF+1,y + + lda __rc3 + sta OAM_BUF+2,y + + tya + clc ; if we can prove Carry is always false, then we don't need this + adc #$04 + sta SPRID + rts + + + +;void oam_meta_spr(unsigned char x,unsigned char y,const unsigned char *data); +;sprid removed +.section .text.oam_meta_spr,"ax",@progbits +.globl oam_meta_spr +oam_meta_spr: + + sta __rc4 + stx __rc5 + ldx SPRID + ldy #0 +1: + lda (__rc2),y ;x offset + cmp #$80 + beq 2f + iny + clc + adc __rc4 + sta OAM_BUF+3,x + lda (__rc2),y ;y offset + iny + clc + adc __rc5 + sta OAM_BUF+0,x + lda (__rc2),y ;tile + iny + sta OAM_BUF+1,x + lda (__rc2),y ;attribute + iny + sta OAM_BUF+2,x + inx + inx + inx + inx + jmp 1b +2: + stx SPRID + rts + +;void oam_hide_rest(void); +;sprid removed +.section .text.oam_hide_rest,"ax",@progbits +.globl oam_hide_rest +oam_hide_rest: + + ldx SPRID + lda #240 + +0: + + sta OAM_BUF,x + inx + inx + inx + inx + bne 0b + ;x is zero + stx SPRID + rts + + diff --git a/mos-platform/nes/neslib/pal_bright.c b/mos-platform/nes/neslib/pal_bright.c new file mode 100644 index 000000000..c1697f53a --- /dev/null +++ b/mos-platform/nes/neslib/pal_bright.c @@ -0,0 +1,25 @@ +// Copyright 2023 LLVM-MOS Project +// Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +// See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +// information. + +__attribute__((section(".zp.pal_bg_ptr"))) volatile const char *PAL_BG_PTR; +__attribute__((section(".zp.pal_spr_ptr"))) volatile const char *PAL_SPR_PTR; +__attribute__((section(".zp.pal_update"))) extern volatile char PAL_UPDATE; + +extern const char __palBrightTableL[]; +extern const char __palBrightTableH[]; +void pal_spr_bright(char bright) { + PAL_SPR_PTR = (const char *)(__palBrightTableH[bright] << 8 | + __palBrightTableL[bright]); + PAL_UPDATE = 1; +} +void pal_bg_bright(char bright) { + PAL_BG_PTR = (const char *)(__palBrightTableH[bright] << 8 | + __palBrightTableL[bright]); + PAL_UPDATE = 1; +} +void pal_bright(char bright) { + pal_spr_bright(bright); + pal_bg_bright(bright); +} diff --git a/mos-platform/nes/neslib/pal_bright.s b/mos-platform/nes/neslib/pal_bright.s new file mode 100644 index 000000000..d97be511c --- /dev/null +++ b/mos-platform/nes/neslib/pal_bright.s @@ -0,0 +1,48 @@ +; Copyright 2023 LLVM-MOS Project +; Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +; See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +; information. + +.section .init.260,"axR",@progbits +.globl pal_bright_init +pal_bright_init: + lda #4 + jsr pal_bright + + +.section .rodata.bright_table,"a",@progbits +.globl __palBrightTableL +.globl __palBrightTableH +__palBrightTableL: + + .byte palBrightTable0@mos16lo,palBrightTable1@mos16lo,palBrightTable2@mos16lo + .byte palBrightTable3@mos16lo,palBrightTable4@mos16lo,palBrightTable5@mos16lo + .byte palBrightTable6@mos16lo,palBrightTable7@mos16lo,palBrightTable8@mos16lo + +__palBrightTableH: + + .byte palBrightTable0@mos16hi,palBrightTable1@mos16hi,palBrightTable2@mos16hi + .byte palBrightTable3@mos16hi,palBrightTable4@mos16hi,palBrightTable5@mos16hi + .byte palBrightTable6@mos16hi,palBrightTable7@mos16hi,palBrightTable8@mos16hi + +palBrightTable0: + .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f ;black +palBrightTable1: + .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f +palBrightTable2: + .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f +palBrightTable3: + .byte $0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f +palBrightTable4: + .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0f,$0f,$0f ;normal colors +palBrightTable5: + .byte $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1a,$1b,$1c,$00,$00,$00 +palBrightTable6: + .byte $10,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$10,$10,$10 ;$10 because $20 is the same as $30 +palBrightTable7: + .byte $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$20,$20,$20 +palBrightTable8: + .byte $30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30 ;white + .byte $30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30 + .byte $30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30 + .byte $30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30,$30 diff --git a/mos-platform/nes/neslib/pal_update.c b/mos-platform/nes/neslib/pal_update.c new file mode 100644 index 000000000..88801ae35 --- /dev/null +++ b/mos-platform/nes/neslib/pal_update.c @@ -0,0 +1,13 @@ +// Copyright 2023 LLVM-MOS Project +// Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +// See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +// information. + +__attribute__((section(".zp.pal_update"))) volatile char PAL_UPDATE; + + +extern volatile char PAL_BUF[]; +void pal_col(char index, char color) { + PAL_BUF[index & 0x1f] = color; + ++PAL_UPDATE; +} diff --git a/mos-platform/nes/neslib/pal_update.s b/mos-platform/nes/neslib/pal_update.s new file mode 100644 index 000000000..9392d536a --- /dev/null +++ b/mos-platform/nes/neslib/pal_update.s @@ -0,0 +1,156 @@ +; Copyright 2023 LLVM-MOS Project +; Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +; See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +; information. + +.zeropage PAL_UPDATE, PAL_BG_PTR, PAL_SPR_PTR + +.include "nes.inc" + +; Place the pallette buffer at the very bottom 32 bytes of the hard stack. +.globl PAL_BUF +PAL_BUF = 0x0100 + +.section .init.265,"axR",@progbits +.globl pal_update_init +pal_update_init: + jsr pal_clear + + +.section .nmi.060,"axR",@progbits +.globl pal_update_nmi +pal_update_nmi: + lda PAL_UPDATE ;update palette if needed + bne .LupdPal + jmp .LskipUpd + +.LupdPal: + + ldx #0 + stx PAL_UPDATE + + lda #$3f + sta PPUADDR + stx PPUADDR + + ldy PAL_BUF ;background color, remember it in X + lda (PAL_BG_PTR),y + sta PPUDATA + tax + + .irp i,0,1,2 + ldy PAL_BUF+1+\i + lda (PAL_BG_PTR),y + sta PPUDATA + .endr + + .irp j,0,1,2 + stx PPUDATA ;background color + .irp i,0,1,2 + ldy PAL_BUF+5+(\j*4)+\i + lda (PAL_BG_PTR),y + sta PPUDATA + .endr + .endr + + .irp j,0,1,2,3 + stx PPUDATA ;background color + .irp i,0,1,2 + ldy PAL_BUF+17+(\j*4)+\i + lda (PAL_SPR_PTR),y + sta PPUDATA + .endr + .endr +.LskipUpd: + + + +;void pal_all(const char *data); +.section .text.pal_all,"ax",@progbits +.global pal_all +pal_all: + + ldx #$00 + lda #$20 + +.Lpal_copy: + + sta __rc4 + + ldy #$00 + +0: + + lda (__rc2),y + sta PAL_BUF,x + inx + iny + dec __rc4 + bne 0b + + inc PAL_UPDATE + + rts + + + +;void pal_bg(const char *data); +.section .text.pal_bg,"ax",@progbits +.globl pal_bg +pal_bg: + + ldx #$00 + lda #$10 + jmp .Lpal_copy + + + +;void pal_spr(const char *data); +.section .text.pal_spr,"ax",@progbits +.globl pal_spr +pal_spr: + + ldx #$10 + txa + jmp .Lpal_copy + + + +;void pal_clear(void); +.section .text.pal_clear,"ax",@progbits +.globl pal_clear +pal_clear: + + lda #$0f + ldx #0 + +0: + + sta PAL_BUF,x + inx + cpx #$20 + bne 0b + stx PAL_UPDATE + rts + + +;void oam_size(unsigned char size); +.section .text.oam_size,"ax",@progbits +.globl oam_size +oam_size: + + asl a + asl a + asl a + asl a + asl a + and #$20 + sta __rc2 + lda PPUCTRL_VAR + and #$df + ora __rc2 + sta PPUCTRL_VAR + + rts + + diff --git a/mos-platform/nes/neslib/rand.s b/mos-platform/nes/neslib/rand.s index 0fdae8c8a..5a383f35e 100644 --- a/mos-platform/nes/neslib/rand.s +++ b/mos-platform/nes/neslib/rand.s @@ -1,6 +1,6 @@ .include "neslib.inc" - .section .init.270,"axR",@progbits + .section .init.255,"axR",@progbits lda #$fd sta RAND_SEED sta RAND_SEED+1 diff --git a/mos-platform/nes/neslib/vram_update.c b/mos-platform/nes/neslib/vram_update.c new file mode 100644 index 000000000..3d05b1783 --- /dev/null +++ b/mos-platform/nes/neslib/vram_update.c @@ -0,0 +1,15 @@ +// Copyright 2023 LLVM-MOS Project +// Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +// See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +// information. + +__attribute__((section(".zp.name_upd_adr"))) volatile const char *NAME_UPD_ADR; +__attribute__((section(".zp.name_upd_enable"))) volatile char NAME_UPD_ENABLE; + +void set_vram_update(const void *buf) { + NAME_UPD_ADR = buf; + NAME_UPD_ENABLE = NAME_UPD_ADR != 0; +} + +// Bring in assembly module +asm (".globl vram_update_nmi"); diff --git a/mos-platform/nes/neslib/vram_update.s b/mos-platform/nes/neslib/vram_update.s new file mode 100644 index 000000000..4b924820c --- /dev/null +++ b/mos-platform/nes/neslib/vram_update.s @@ -0,0 +1,113 @@ +; Copyright 2023 LLVM-MOS Project +; Licensed under the Apache License, Version 2.0 with LLVM Exceptions. +; See /~https://github.com/llvm-mos/llvm-mos-sdk/blob/main/LICENSE for license +; information. + +.zeropage NAME_UPD_ADR, NAME_UPD_ENABLE + +.include "nes.inc" +.include "neslib.inc" + +.section .init.280,"axR",@progbits +.globl vram_update_init +vram_update_init: + lda #0 + sta __rc2 + sta __rc3 + jsr set_vram_update + + +.section .nmi.065,"axR",@progbits +.globl vram_update_nmi +vram_update_nmi: + lda NAME_UPD_ENABLE + beq .LskipUpd + jsr flush_vram_update2 +.LskipUpd: + + +;void flush_vram_update(unsigned char *buf); +.section .text.flush_vram_update,"axR",@progbits +.globl flush_vram_update +flush_vram_update: + lda __rc2 + sta NAME_UPD_ADR+0 + lda __rc3 + sta NAME_UPD_ADR+1 + +.globl flush_vram_update2 +flush_vram_update2: ;minor changes % + + ldy #0 + +.LupdName: + ; First byte is upper PPU address or #$ff if done + lda (NAME_UPD_ADR),y + iny + cmp #$40 ; bits 6 and 7 indicate sequential ops + bcc .LupdSingle + + ; save upper address byte for arithmetic + tax + lda PPUCTRL_VAR + cpx #$80 ; below 80 is horizontal + bmi .LupdHorzSeq + cpx #$ff + beq .LupdDone + +.LupdVertSeq: + ; Set control bit for vertical traversal + ora #$04 ; TODO constants for ctrl flags? + bne .LupdNameSeq ;always taken + +.LupdSingle: + sta PPUADDR + lda (NAME_UPD_ADR),y ; address lo + iny + sta PPUADDR + lda (NAME_UPD_ADR),y ; data + iny + sta PPUDATA + bne .LupdName ; always taken. Assumes index never wraps + +.LupdHorzSeq: + ; Clear control bit for vertical traversal + and #$fb + +.LupdNameSeq: + ; Store new control value + sta PPUCTRL + + ; Mask out top 2 bits of upper address byte + txa + and #$3F + + sta PPUADDR + lda (NAME_UPD_ADR),y ; address lo + iny + sta PPUADDR + lda (NAME_UPD_ADR),y ; size + iny + + ; store size in counter + tax + +.LupdNameLoop: + + lda (NAME_UPD_ADR),y + iny + sta PPUDATA + dex + bne .LupdNameLoop + + lda PPUCTRL_VAR + sta PPUCTRL + + jmp .LupdName + +.LupdDone: + jmp __post_vram_update + +.weak __post_vram_update +__post_vram_update: + rts