gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit 9e9511a12ca4f104d74f03d89fbf0e2430a09c82 parent c9792eb8cafc5fff63b7c6faf03c6883ae7adac5 Author: Toxa <56631470+untoxa@users.noreply.github.com> Date: Sat, 18 May 2024 15:08:27 +0300 Merge pull request #671 from michel-iwaniec/nes_add_bcd_support NES: Add BCD support Diffstat:
| M | gbdk-lib/examples/cross-platform/bcd/Makefile | 2 | +- |
| M | gbdk-lib/include/gbdk/bcd.h | 2 | ++ |
| A | gbdk-lib/include/nes/bcd.h | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | gbdk-lib/libc/asm/mos6502/Makefile | 1 | + |
| A | gbdk-lib/libc/asm/mos6502/bcd.s | 283 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
5 files changed, 348 insertions(+), 1 deletion(-)
diff --git a/gbdk-lib/examples/cross-platform/bcd/Makefile b/gbdk-lib/examples/cross-platform/bcd/Makefile @@ -11,7 +11,7 @@ LCC = $(GBDK_HOME)bin/lcc # Set platforms to build here, spaced separated. (These are in the separate Makefile.targets) # They can also be built/cleaned individually: "make gg" and "make gg-clean" # Possible are: gb gbc pocket megaduck sms gg -TARGETS=gb pocket megaduck sms gg +TARGETS=gb pocket megaduck sms gg nes # Configure platform specific LCC flags here: LCCFLAGS_gb = -Wl-yt0x1B # Set an MBC for banking (1B-ROM+MBC5+RAM+BATT) diff --git a/gbdk-lib/include/gbdk/bcd.h b/gbdk-lib/include/gbdk/bcd.h @@ -5,6 +5,8 @@ #include <gb/bcd.h> #elif defined(__TARGET_sms) || defined(__TARGET_gg) || defined(__TARGET_msxdos) #include <sms/bcd.h> +#elif defined(__TARGET_nes) + #include <nes/bcd.h> #else #error Unrecognized port #endif diff --git a/gbdk-lib/include/nes/bcd.h b/gbdk-lib/include/nes/bcd.h @@ -0,0 +1,61 @@ +#ifndef __BCD_H_INCLUDE +#define __BCD_H_INCLUDE + +#include <types.h> +#include <stdint.h> + +/** @file bcd.h + Support for working with BCD (Binary Coded Decimal) + + See the example BCD project for additional details. +*/ + +// macro for creating BCD constants +#define BCD_HEX(v) ((BCD)(v)) + +/** Converts an integer value into BCD format + + A maximum of 8 digits may be used +*/ +#define MAKE_BCD(v) BCD_HEX(0x ## v) + +typedef uint32_t BCD; + +/** Converts integer __i__ into BCD format (Binary Coded Decimal) + @param i Numeric value to convert + @param value Pointer to a BCD variable to store the converted result +*/ +void uint2bcd(uint16_t i, BCD * value) OLDCALL; + +/** Adds two numbers in BCD format: __sour__ += __value__ + @param sour Pointer to a BCD value to add to (and where the result is stored) + @param value Pointer to the BCD value to add to __sour__ +*/ +void bcd_add(BCD * sour, const BCD * value) OLDCALL; + +/** Subtracts two numbers in BCD format: __sour__ -= __value__ + @param sour Pointer to a BCD value to subtract from (and where the result is stored) + @param value Pointer to the BCD value to subtract from __sour__ +*/ +void bcd_sub(BCD * sour, const BCD * value) OLDCALL; + +/** Convert a BCD number into an asciiz (null terminated) string and return the length + @param bcd Pointer to BCD value to convert + @param tile_offset Optional per-character offset value to add (use 0 for none) + @param buffer Buffer to store the result in + + Returns: Length in characters (always 8) + + __buffer__ should be large enough to store the converted string + (9 bytes: 8 characters + 1 for terminator) + + There are a couple different ways to use __tile_offset__. + For example: + \li It can be the Index of the Font Tile '0' in VRAM to + allow the buffer to be used directly with @ref set_bkg_tiles. + \li It can also be set to the ascii value for character '0' + so that the buffer is a normal string that can be passed to @ref printf. +*/ +uint8_t bcd2text(const BCD * bcd, uint8_t tile_offset, uint8_t * buffer) OLDCALL; + +#endif diff --git a/gbdk-lib/libc/asm/mos6502/Makefile b/gbdk-lib/libc/asm/mos6502/Makefile @@ -12,6 +12,7 @@ ASSRC = __sdcc_indirect_jsr.s _memcpy.s _strcpy.s _strcmp.s _memset.s \ _mulint.s \ _mullong.s \ _muluchar.s _mulschar.s \ + bcd.s \ _setjmp.s \ _dptr.s _ret01.s _ret23.s _ret4567.s _temp.s diff --git a/gbdk-lib/libc/asm/mos6502/bcd.s b/gbdk-lib/libc/asm/mos6502/bcd.s @@ -0,0 +1,283 @@ +;-------------------------------------------------------------------------- +; bcd.s +; +; Copyright (C) 2024, Michel Iwaniec +; +; This library is free software; you can redistribute it and/or modify it +; under the terms of the GNU General Public License as published by the +; Free Software Foundation; either version 2, or (at your option) any +; later version. +; +; This library is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this library; see the file COPYING. If not, write to the +; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, +; MA 02110-1301, USA. +; +; As a special exception, if you link this library with other files, +; to produce an executable, this library does not by itself cause the +; resulting executable to be covered by the GNU General Public License. +; This exception does not however invalidate any other reasons why the +; executable file might be covered by the GNU General Public License. +;-------------------------------------------------------------------------- + +.module bcd + +.area OSEG (PAG, OVR) +_bcd2text_bcd: +_bcd2text_tile_offset: +_bcd2text_PARM_2:: .ds 1 +_bcd2text_buffer: +_bcd2text_PARM_3:: .ds 2 +_bcd2text_BCD: .ds 4 +_bcd_sub_PARM_2:: +_uint2bcd_PARM_2:: +_bcd_add_PARM_2:: .ds 4 + +.area _HOME + +; void uint2bcd(uint16_t i, BCD * value) __naked +_uint2bcd:: + .define tmp "REGTEMP+2" + .define losub "REGTEMP+4" + .define hisub "REGTEMP+5" + .define v "REGTEMP+6" + ;.define value "_uint2bcd_PARM_2" + + sta *tmp + stx *tmp+1 + ; First two digits are always for uint16 -> BCD conversion + ldy #3 + lda #0 + sta [*_uint2bcd_PARM_2],y + dey + lda #0xFF + sta *v + tax + jmp 4$ +1$: + inc *v + lda *tmp + sec + sbc *losub + sta *tmp + lda *tmp+1 + sbc *hisub + sta *tmp+1 + bcs 1$ + ; Undo last sub. This should be faster on average + lda *tmp + adc *losub + sta *tmp + lda *tmp+1 + adc *hisub + sta *tmp+1 + ; Check odd/even x to determine if upper/lower nibble completed. + txa + lsr + lda *v + bcc 3$ + ; Upper digit completed. Shift value to upper nibble. + asl + asl + asl + asl + adc #0xFF + sta *v + jmp 4$ +3$: + ; Lower digit completed. Write value, move index and re-initialize v. + sta [*_uint2bcd_PARM_2],y + lda #0xFF + sta *v + dey + beq 5$ +4$: + inx + lda losub_tab,x + sta *losub + lda hisub_tab,x + sta *hisub + jmp 1$ +5$: + ; Switch to single-byte mode for second-last digit + ldx #0xFF + lda *tmp +6$: + inx + sec + sbc #10 + bcs 6$ + ; Undo last sub + adc #10 + ; Combine last digit with second-last + and #0x0F + sta *tmp + txa + asl + asl + asl + asl + ora *tmp + ; Write combined result + sta [*_uint2bcd_PARM_2],y + rts + +losub_tab: +.db <10000 +.db <1000 +.db <100 + +hisub_tab: +.db >10000 +.db >1000 +.db >100 + +;void bcd_add(BCD * sour, BCD * value) __naked +_bcd_add:: + .define sour "REGTEMP" + .define value "_bcd_add_PARM_2" + ;.define tmp "REGTEMP+2" + .define .c "REGTEMP+3" + .define .n "REGTEMP+4" + sta *sour + stx *sour+1 + ldy #0 + lda #4 + sta *.n + clc +1$: + lda [*sour],y + adc [*value],y + ror *.c + tax + eor [*sour],y + eor [*value],y + and #0x10 + ; Add 0x06 if half-carry was set + bne 2$ + ; ...or if low nibble result >= 0xA + txa + and #0x0F + cmp #0x0A + txa + bcc 3$ +2$: + txa + clc + adc #0x06 +3$: + ; Add 0x60 if carry was set + bit *.c + bmi 4$ + ; ...or if high nibble result >= 0xA + cmp #0xA0 + bcc 5$ +4$: + clc + adc #0x60 + sec +5$: + sta [*sour],y + iny + dec *.n + bne 1$ + rts + +; void bcd_sub(BCD * sour, BCD * value) __naked +_bcd_sub:: + .define sour "REGTEMP" + .define value "_bcd_add_PARM_2" + .define tmp "REGTEMP+2" + .define .c "REGTEMP+3" + .define .n "REGTEMP+4" + sta *sour + stx *sour+1 + ldy #0 + lda #4 + sta *.n + sec +1$: + lda [*sour],y + sbc [*value],y + ror *.c + tax + eor [*sour],y + eor [*value],y + and #0x10 + ; Add 0x06 if half-carry was set + bne 2$ + ; ...or if low nibble result >= 0xA + txa + and #0x0F + cmp #0x0A + txa + bcc 3$ +2$: + txa + clc + adc #0x06 +3$: + ; Add 0x60 if carry was *clear* + bit *.c + bpl 4$ + ; ...or if high nibble result >= 0xA + cmp #0xA0 + bcc 5$ +4$: + clc + adc #0x60 + clc + bcc 6$ +5$: + sec +6$: + sta [*sour],y + iny + dec *.n + bne 1$ + rts + +;uint8_t bcd2text(BCD * bcd, uint8_t tile_offset, uint8_t * buffer) __naked +_bcd2text:: + sta *REGTEMP + stx *REGTEMP+1 + + ldy #3 +0$: + lda [*REGTEMP],y + sta *_bcd2text_BCD,y + dey + bpl 0$ + + ldy #0 + ldx #3 +1$: + lda *_bcd2text_BCD,x + pha + lsr + lsr + lsr + lsr + clc + adc *_bcd2text_tile_offset + sta [*_bcd2text_buffer],y + iny + pla + and #0x0F + clc + adc *_bcd2text_tile_offset + sta [*_bcd2text_buffer],y + iny + dex + bpl 1$ + ; Store 0 at end + lda #0 + sta [*_bcd2text_buffer],y + ; Return length of string as 8 + lda #8 + rts
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.