In order to do this, you need to write a 16 bit math library: addition, subtraction, multiplication, division. The first two are relativly easy, just add the low and the hight byte and add or subtract the carry bit. For multiplication you may use the russian multipication algorythm (see for example https://www.wikihow.com/Multiply-Using-the-Russian-Peasant-Method) which only works by shifting a binary number and addition. Divison works like you divide on paper. You may convert z80 assembly to chip8. For example from here: https://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division or for 6502 (https://llx.com/Neil/a2/mult.html) with good explanation of the algorythm.
Lazy Multiplication by 10 can be done by
x = x + x ; *2
y = x
x = x + x ; *4
x = x + x ; * 8
x = x + y; * 10
You have to use your 16bit addition here and work with two registers. There is no lazy divide by 10
If you have all this, you can start decoding the number to decimal.
The last digit you get by
1. Divide by 10.
2. Multiply by 10.
3. Take difference.
Repeat this until the number is 0
You may also work the other way around.
digit1 = x / 1000
x = x / 10
digit2 = x / 100
x = x / 10
digit3 = x / 10
digit4 = x
As a general rule, I'd strongly recommend against starting with a collection of general-purpose routines; they will often do much more work than is actually necessary for a given application, wasting cycles and RAM.
Start with the game concept, and sketch out the design. For all data structures- including number representations- look at the ways your game will use them, and choose representations which make those operations easy.
An efficient program will flow from appropriate choices of data layout and structure. Different design constraints ask for different representations.