refactor the "decode_and_execute" function of this python code.
Write the refactored function first, leave the explainations for later

import random
import os
import keyboard
from timeit import default_timer as functiontimer

# 8 bit general purpose registers
registers = {f"V{i:x}": 0 for i in range(16)}

# 8 bit flag registers
registers["Vf"] = 0

# 16 bit register (only the lowest 12 bit usually used)
registers["I"] = 0

# Timer registers
timer_registers = {
    "DT": 0, # Delay Timer Register
    "ST": 0  # Sound Timer Register
}

# Keypad
keypad = {f"K{i:x}": 0 for i in range(16)}

# Memory from 0 (0x000) to 4095 (0xFFF)
memory = [0] * 4096

# 64-byte stack
stack = [0] * 64

# 8x64 monochrome framebuffer
framebuffer = [[0 for _ in range(64)] for _ in range(32)]

screen_needs_redraw = True
pc = 0x200 # 16 bit

# Keyboard and screen helpers
def update_keypad():
    global keypad

    def update_keypad_row(row, key_indexes):
        for i, key_index in enumerate(key_indexes):
            if keyboard.is_pressed(row[i]):
                keypad[f"K{key_index}"] = 1

    # First row
    update_keypad_row("1234", [1, 2, 3, 0xC])

    # Second row
    update_keypad_row("qwer", [4, 5, 6, 0xD])

    # Third row
    update_keypad_row("asdf", [7, 8, 9, 0xE])

    # Fourth row
    update_keypad_row("zxcv", [0xA, 0, 0xB, 0xF])

def wait_for_keypress():
    while True:
        keys = [
            ["1234", 0x1, 0x2, 0x3, 0xC],
            ["qwer", 0x4, 0x5, 0x6, 0xD],
            ["asdf", 0x7, 0x8, 0x9, 0xE],
            ["zxcv", 0xA, 0x0, 0xB, 0xF]
        ]

        for row in keys:
            if keyboard.is_pressed(row[0]):
                return row[1 + row.index(True)]

def reset_keypad():
    global keypad
    keypad = {f"K{i:x}": 0 for i in range(16)}

# Function to load the binary at 0+offset in memory
def load_binary(filename, offset):
    global memory

    counter = offset
    with open(filename, "rb") as f:
        while byte := f.read(1):
            memory[counter] = int.from_bytes(byte, byteorder="big")
            counter += 1


def decode_and_execute(instr):
	global memory
	global stack
	global pc
	global registers
	global timer_registers
	global framebuffer
	global keypad
	global screen_needs_redraw

	did_instruction_branch = False

	##USEFUL PARAMETERS
	nnn = int(instr[1] + instr[2] + instr[3],16)
	vx = 'V' + instr[1]
	vy = 'V' + instr[2]
	kk = int(instr[2] + instr[3],16)

	if instr[0] == '0':
		if instr[1] == '0' and instr[2] == 'e' and instr[3] == '0': #CLS
			framebuffer = [[0 for _ in range(64)] for _ in range(32)]
		elif instr[1] == '0' and instr[2] == 'e' and instr[3] == 'e': #RET
			pc = stack.pop() + 2
			did_instruction_branch = True
		else: #SYS nnn
			pass
	
	elif instr[0] == '1': #'JP 0x0' + nnn
		pc = nnn
		did_instruction_branch = True

	elif instr[0] == '2': # 'CALL 0x0' + nnn
		stack.append(pc)
		pc = nnn 
		did_instruction_branch = True

	#OK
	elif instr[0] == '3': #'SE' + vx_byte
		if registers[vx] == kk:
			pc += 2

	#OK
	elif instr[0] == '4': #'SNE' + vx_byte
		if registers[vx] != kk:
			pc += 2

	#OK
	elif instr[0] == '5': #'SE' + vx_vy
		if registers[vx] == registers[vy]:
			pc += 2

	#TO_TEST
	elif instr[0] == '6': #'LD' + vx_byte
		registers[vx] = kk 

	#OK
	elif instr[0] == '7': #'ADD' + vx_byte
		if registers[vx] + kk > 255:
			registers[vx] = registers[vx] + kk - 256
		else:
			registers[vx] = registers[vx] + kk

	#OK (all 8xxn)
	elif instr[0] == '8':
		if instr[3] == '0': #'LD' + vx_vy
			registers[vx] = registers[vy]
		elif instr[3] == '1': #'OR' + vx_vy
			registers[vx] = registers[vx] | registers[vy]
		elif instr[3] == '2': #'AND' + vx_vy
			registers[vx] = registers[vx] & registers[vy]
		elif instr[3] == '3': #'XOR' + vx_vy
			registers[vx] = registers[vx] ^ registers[vy]
		elif instr[3] == '4': #'ADD' + vx_vy
			if registers[vx] + registers[vy] > 255:
				registers[vx] = registers[vx] + registers[vy] - 256
				registers['Vf'] = 1
			else:
				registers[vx] = registers[vx] + registers[vy]
				registers['Vf'] = 0
		elif instr[3] == '5': #'SUB' + vx_vy
			if registers[vx] > registers[vy]:
				registers['Vf'] = 1
				registers[vx] = registers[vx] - registers[vy]
			else:
				registers['Vf'] = 0
				registers[vx] = 256 + registers[vx] - registers[vy]
		elif instr[3] == '6': #'SHR' + vx_vy_braces
			lsb = registers[vx] & 1
			registers['Vf'] = lsb
			registers[vx] = registers[vx] >> 1 ## we're dividing, no problem
		elif instr[3] == '7': #'SUBN' + vx_vy
			if registers[vy] > registers[vx]:
				registers[vx] = registers[vy] - registers[vx]
				registers['Vf'] = 1
			else:
				registers[vx] = 256 + registers[vy] - registers[vx]
				registers['Vf'] = 0
		elif instr[3] == 'e': #'SHL' + vx_vy_braces
			msb = int("{0:08b}".format(registers[vx])[:1])
			registers['Vf'] = msb
			if registers[vx] << 1 > 255:
				registers[vx] = (registers[vx] << 1) - 256
			else:
				registers[vx] = registers[vx] << 1

	#OK
	elif instr[0] == '9': #'SNE' + vx_vy
		if registers[vx] != registers[vy]:
			pc += 2

	#OK
	elif instr[0] == 'a': #'LD I 0x0' + nnn
		registers['I'] = nnn
 
	#OK
	elif instr[0] == 'b': #'JP V0' + nnn 
		pc = nnn + registers['V0']
		did_instruction_branch = True

	#OK
	elif instr[0] == 'c': #'RND' + vx_byte
		registers[vx] = kk & random.randint(0,255)

	#OK
	elif instr[0] == 'd': #'DRW' + vx_vy + ' 0x' + instr[3]
		screen_needs_redraw = True
		height = int('0x' + instr[3],16)
		base_ptr = registers['I']
		registers['Vf'] = 0
		
		for y_index in range(height):
			sprite_byte = format(int(str(hex(memory[base_ptr + y_index]))[2:].zfill(2),16), '08b')
			for x_index in range(8):
				color = int(sprite_byte[x_index])
				pos_vx = (registers[vx] + x_index) % 64
				pos_vy = ((registers[vy] + y_index) % 32)

				if framebuffer[pos_vy][pos_vx] == 1 and color == 1:
					registers['Vf'] = registers['Vf'] | 1
					color = 0
				elif framebuffer[pos_vy][pos_vx] == 1 and color == 0:
					color = 1

				framebuffer[pos_vy][pos_vx] = color

	elif instr[0] == 'e':
		if instr[2] == '9' and instr[3] == 'e': #return 'SKP' + vx
			updateKeypad()
			if keypad['K'+ str(hex(registers[vx])[-1])] == 1:
				pc += 2
			resetKeypad()
		elif instr[2] == 'a' and instr[3] == '1': #return 'SKNP' + vx
			updateKeypad()
			if keypad['K'+ str(hex(registers[vx])[-1])] == 0:
				pc += 2
			resetKeypad()

	elif instr[0] == 'f':
		#TO_TEST
		if instr[2] == '0' and instr[3] == '7': #'LD' + vx + ', DT'
			registers[vx] = timer_registers['DT']
		#OK
		elif instr[2] == '0' and instr[3] == 'a': #return 'LD' + vx + ', K' 
			registers[vx] = waitForKeypress()
		#OK
		elif instr[2] == '1' and instr[3] == '5': #'LD DT,' + vx
			timer_registers['DT'] = registers[vx]
		#OK
		elif instr[2] == '1' and instr[3] == '8': #'LD ST,' + vx
			 timer_registers['ST'] = registers[vx]
		#OK
		elif instr[2] == '1' and instr[3] == 'e': #'ADD I,' + vx
			registers['I'] = registers['I'] + registers[vx]
		#OK
		elif instr[2] == '2' and instr[3] == '9': #'LD F,' + vx
			registers['I'] = registers[vx] *5
		#OK
		elif instr[2] == '3' and instr[3] == '3': #'LD B,' + vx
			base_ptr = registers['I']
			memory[base_ptr] = registers[vx] // 10**2 % 10
			memory[base_ptr + 1] = registers[vx] // 10**1 % 10
			memory[base_ptr + 2] = registers[vx] // 10**0 % 10
		#OK	
		elif instr[2] == '5' and instr[3] == '5': #'LD [I],' + vx
			base_ptr = registers['I']
			for i in range(int(vx[1:]) +1):
				memory[base_ptr + i] = registers['V'+str(i)] 
		#OK
		elif instr[2] == '6' and instr[3] == '5': #'LD' + vx + ', [I]'
			base_ptr = registers['I']
			for i in range(int(vx[1:],16) +1):
				registers['V'+str(i)] = memory[base_ptr + i]

	#Now we check if we need to increment the program counter or if we are gonna branch
	if did_instruction_branch == False:
		pc += 2
	
def print_mem_as_hex(): #This is a DEBUG function
	global memory
	print('{}'.format('\n'.join('{:02x}'.format(x) for x in memory)))


def update_screen():
	global framebuffer

	output = ''
	os.system('cls')
	for column in framebuffer:
			output += ''.join((str(i) + ' ') for i in column).join(os.linesep)
	print(output.replace('0', ' ').replace('1', '#'))



def main():
	global memory
	global pc
	global screen_needs_redraw

	#loading the fonts in memory
	load_binary('chip8_fonts.bin', 0)

	#loading the rom in memory
	load_binary('maze.ch8', 512)
	#load_binary('bmp.ch8', 512)
	#load_binary('ibm.ch8', 512)
	#load_binary('chip8logo.ch8', 512)
	#load_binary('test_opcode.ch8', 512)
	#load_binary('c8_test.ch8', 512)
	#load_binary('trip.ch8', 512)
	#load_binary('rush_hour.ch8', 512)
	#load_binary('space_invaders.ch8', 512)
	#load_binary('chip8-test-rom.ch8', 512)
	#load_binary('keypad_test.ch8', 512)

	clockcycles = 0
	timer_period = 1.0 / 60 #1/calls per second
	timer_start_time = functiontimer()

	while True:

		if (functiontimer() - timer_start_time) > timer_period:
			if timer_registers['DT'] > 0: ##Decrement sound registers
				timer_registers['DT'] -= 1
			if timer_registers['ST'] > 0:
				timer_registers['ST'] -= 1
			timer_start_time = functiontimer()
		
		if screen_needs_redraw:
			update_screen()
			screen_needs_redraw = False	
		
		instruction = str(hex(memory[pc]))[2:].zfill(2) + str(hex(memory[pc+1]))[2:].zfill(2)

		decode_and_execute(instruction)


if __name__ == '__main__':
	main()