0
\$\begingroup\$

I'm making an emulator for the chip-8 using the Godot 4.3 game engine, It's almost complete and you can play pong on it perfectly fine, But it can't display numbers from the built in font.

Each character is 4 pixels wide and 5 pixels high. The character 0 has the encoding 0xF0, 0x90, 0x90, 0x90, 0xF0 which is interpreted as follows:

hex bin pixels
0xF0 1111 ████
0x90 1001 █ █
0x90 1001 █ █
0x90 1001 █ █
0xF0 1111 ████

Here's my font as packed byte array:

# RAM var RAM: PackedByteArray = [] # Built in font: var font: PackedByteArray = [ 0xF0, 0x90, 0x90, 0x90, 0xF0, # 0 0x20, 0x60, 0x20, 0x20, 0x70, # 1 0xF0, 0x10, 0xF0, 0x80, 0xF0, # 2 0xF0, 0x10, 0xF0, 0x10, 0xF0, # 3 0x90, 0x90, 0xF0, 0x10, 0x10, # 4 0xF0, 0x80, 0xF0, 0x10, 0xF0, # 5 0xF0, 0x80, 0xF0, 0x90, 0xF0, # 6 0xF0, 0x10, 0x20, 0x40, 0x40, # 7 0xF0, 0x90, 0xF0, 0x90, 0xF0, # 8 0xF0, 0x90, 0xF0, 0x10, 0xF0, # 9 0xF0, 0x90, 0xF0, 0x90, 0x90, # A 0xE0, 0x90, 0xE0, 0x90, 0xE0, # B 0xF0, 0x80, 0x80, 0x80, 0xF0, # C 0xE0, 0x90, 0x90, 0x90, 0xE0, # D 0xF0, 0x80, 0xF0, 0x80, 0xF0, # E 0xF0, 0x80, 0xF0, 0x80, 0x80 # F ] func _ready() -> void: # Other code... # Load font into RAM: var offset: int = 0x50 for i: int in font: RAM[offset] = i offset += 1 var rom: PackedByteArray = open_read_and_get_ROM("rom_path_here") load_rom_into_ram(rom) func load_rom_into_ram(ROM: PackedByteArray) -> void: var offset: int = 0x200 for i: int in ROM: RAM[offset] = i offset += 1 

chip-8 roms are supposed to use the font that's already built in to your emulator, But the roms I try display nonsense instead of displaying actual hex numbers.

I really don't think there's anything wrong with the draw instruction because It can draw anything else perfectly but here it is anyway:

 0xD000: # 1st nibble is 'D': # DXYN: Draws a sprite at coordinate (VX, VY)... registers[0xF] = 0 # VF register must be cleared first. var x_pos: int = registers[opcode >> 8 & 0xF] % 64 var y_pos: int = registers[opcode >> 4 & 0xF] % 32 for N: int in range(opcode & 0x000F): var Nth_byte: int = RAM[index_register + N] for i: int in range(8): if x_pos >= 64: x_pos = x_pos % 64 # wrap coordinates when reaching end of screen. screen[x_pos][y_pos] = screen[x_pos][y_pos] ^ (Nth_byte << i & 0b10000000) if screen[x_pos][y_pos] ^ (Nth_byte << i & 0b10000000) != 0: # Check if pixel collision. registers[0xF] = 1 # add 1 to the flag register VF. x_pos += 1 y_pos += 1 x_pos -= 8 if y_pos >= 32: y_pos = y_pos % 32 # wrap coordinates when reaching end of screen. queue_redraw() 

My emulator: The score is meant to be displayed on the top, But it's displaying nonsense. enter image description here Expected result: enter image description here enter image description here

\$\endgroup\$
3
  • 3
    \$\begingroup\$ It might be a good idea to explain the logic of how this is supposed to work in a bit more detail, to help Godot experts who might not be experts in chip-8 get up to speed so they can answer your question. \$\endgroup\$ Commented Apr 3 at 14:53
  • 2
    \$\begingroup\$ I don't know enough about this, but general advice: go step by step with the debugger and check it is doing what you expect (that it is getting on the correct branch of the code and has sane values, etc). \$\endgroup\$ Commented Apr 3 at 16:07
  • 1
    \$\begingroup\$ Out of curiosity I poked around a little and I see some people saying there are 2 traditional offsets for fonts: x0 for small fonts; x50 for super chip- large font. I don't know enough about the topic to know how your emulator knows where the font is located, but I also saw a discussion where the programmer suggested it is arbitrary. Confusing. So if you are packing the small font into the expected large font area, the rows and columns might be off and there may not be enough data? \$\endgroup\$ Commented Apr 3 at 21:45

1 Answer 1

0
\$\begingroup\$

Oops! I forgot to interpret exactly one very important opcode: FX29, which is used to draw the font:

FX29: Set I to the memory address of the sprite data corresponding to the hexadecimal digit stored in register VX

or in pseudocode: I = sprite_addr[Vx].

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This answer would be more useful for future readers if you explain in a bit more detail how you interpret this opcode. \$\endgroup\$ Commented Apr 5 at 14:19

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.