// File: nicoeps[P]NicoGB/src/memory.cpp
// Function: Memory::write(unsigned short, unsigned char)
void Memory::write(uint16_t address, uint8_t n) {
    if (address <= 0x7FFF && cartridge.loaded == true) {
        cartridge.write(address, n);
    } else if (address >= 0x8000 && address <= 0x9FFF) {
        vram[address - 0x8000] = n;
    } else if (address >= 0xA000 && address <= 0xBFFF) {
        cartridge.write(address, n); 
    } else if (address >= 0xC000 && address <= 0xDFFF) {
        wram[address - 0xC000] = n;
    } else if (address >= 0xE000 && address <= 0xFDFF) {
        wram[address - 0xE000] = n;
    } else if (address >= 0xFE00 && address <= 0xFE9F) {
        oam[address - 0xFE00] = n;
    } else if ((address >= 0xFF00 && address <= 0xFF7F) || address == 0xFFFF) {
        switch (address) {
            case 0xFF00: joypad.write(n); break;
            case 0xFF04: timer.counter = 0; break;
            case 0xFF05: timer.tima = n; break;
            case 0xFF06: timer.tma = n; break;
            case 0xFF07: timer.tac = n | 0xF8; break;
            case 0xFF40: lcd.lcdc = n; break;
            case 0xFF41: lcd.stat = (lcd.stat & 0x7) | (n & 0x78) | 0x80; break;
            case 0xFF42: lcd.scy = n; break;
            case 0xFF43: lcd.scx = n; break;
            case 0xFF45: lcd.lyc = n; break;
            case 0xFF46: // DMA Transfer
                io[0x46] = n;
                if (dmaCycle > 0xA0) {
                    dmaAddress = n << 8;
                    dmaCycle = 0x0;
                }
                break;
            case 0xFF47: lcd.bgp = n; break;
            case 0xFF48: lcd.obp0 = n; break;
            case 0xFF49: lcd.obp1 = n; break;
            case 0xFF4A: lcd.wy = n; break;
            case 0xFF4B: lcd.wx = n; break;
            case 0xFF50:
                if (n == 0x01 && bootEnabled) {
                    bootEnabled = false;
                    write(0xFF10, 0x80); // NR10
                    write(0xFF11, 0xBF); // NR11
                    write(0xFF12, 0xF3); // NR12
                    write(0xFF14, 0xBF); // NR14
                    write(0xFF16, 0x3F); // NR21
                    write(0xFF17, 0x00); // NR22
                    write(0xFF19, 0xBF); // NR24
                    write(0xFF1A, 0x7F); // NR30
                    write(0xFF1B, 0xFF); // NR31
                    write(0xFF1C, 0x9F); // NR32
                    write(0xFF1E, 0xBF); // NR33
                    write(0xFF20, 0xFF); // NR41
                    write(0xFF21, 0x00); // NR42
                    write(0xFF22, 0x00); // NR43
                    write(0xFF23, 0xBF); // NR30
                    write(0xFF24, 0x77); // NR50
                    write(0xFF25, 0xF3); // NR51
                    write(0xFF26, 0xF1); // NR52
                }
                break;
            case 0xFFFF: io[0xFF] = n; break; // IE
            case 0xFF0F: io[0x0F] = n | 0xE0; break; // IF
            default: io[address - 0xFF00] = n; break;
        }
    } else if (address >= 0xFF80 && address <= 0xFFFE) {
        hram[address - 0xFF80] = n;
    }
}

// Assembly:
subq $0x28, %rsp
movb %dl, %al
movw %si, %cx
movq %rdi, 0x20(%rsp)
movw %cx, 0x1e(%rsp)
movb %al, 0x1d(%rsp)
movq 0x20(%rsp), %rax
movq %rax, 0x10(%rsp)
movzwl 0x1e(%rsp), %eax
cmpl $0x7fff, %eax           # imm = 0x7FFF
jg 0xe8a1
movq 0x10(%rsp), %rax
movq (%rax), %rax
movb 0x20(%rax), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0xe8a1
movq 0x10(%rsp), %rax
movq (%rax), %rdi
movw 0x1e(%rsp), %ax
movzwl %ax, %esi
movzbl 0x1d(%rsp), %edx
callq 0x3e80
jmp 0xef2a
movzwl 0x1e(%rsp), %eax
cmpl $0x8000, %eax           # imm = 0x8000
jl 0xe8e7
movzwl 0x1e(%rsp), %eax
cmpl $0x9fff, %eax           # imm = 0x9FFF
jg 0xe8e7
movq 0x10(%rsp), %rdi
movb 0x1d(%rsp), %al
movb %al, 0xf(%rsp)
addq $0x28, %rdi
movzwl 0x1e(%rsp), %eax
subl $0x8000, %eax           # imm = 0x8000
movslq %eax, %rsi
callq 0x40f0
movb 0xf(%rsp), %cl
movb %cl, (%rax)
jmp 0xef28
movzwl 0x1e(%rsp), %eax
cmpl $0xa000, %eax           # imm = 0xA000
jl 0xe91e
movzwl 0x1e(%rsp), %eax
cmpl $0xbfff, %eax           # imm = 0xBFFF
jg 0xe91e
movq 0x10(%rsp), %rax
movq (%rax), %rdi
movw 0x1e(%rsp), %ax
movzwl %ax, %esi
movzbl 0x1d(%rsp), %edx
callq 0x3e80
jmp 0xef26
movzwl 0x1e(%rsp), %eax
cmpl $0xc000, %eax           # imm = 0xC000
jl 0xe964
movzwl 0x1e(%rsp), %eax
cmpl $0xdfff, %eax           # imm = 0xDFFF
jg 0xe964
movq 0x10(%rsp), %rdi
movb 0x1d(%rsp), %al
movb %al, 0xe(%rsp)
addq $0x40, %rdi
movzwl 0x1e(%rsp), %eax
subl $0xc000, %eax           # imm = 0xC000
movslq %eax, %rsi
callq 0x40f0
movb 0xe(%rsp), %cl
movb %cl, (%rax)
jmp 0xef24
movzwl 0x1e(%rsp), %eax
cmpl $0xe000, %eax           # imm = 0xE000
jl 0xe9aa
movzwl 0x1e(%rsp), %eax
cmpl $0xfdff, %eax           # imm = 0xFDFF
jg 0xe9aa
movq 0x10(%rsp), %rdi
movb 0x1d(%rsp), %al
movb %al, 0xd(%rsp)
addq $0x40, %rdi
movzwl 0x1e(%rsp), %eax
subl $0xe000, %eax           # imm = 0xE000
movslq %eax, %rsi
callq 0x40f0
movb 0xd(%rsp), %cl
movb %cl, (%rax)
jmp 0xef22
movzwl 0x1e(%rsp), %eax
cmpl $0xfe00, %eax           # imm = 0xFE00
jl 0xe9f0
movzwl 0x1e(%rsp), %eax
cmpl $0xfe9f, %eax           # imm = 0xFE9F
jg 0xe9f0
movq 0x10(%rsp), %rdi
movb 0x1d(%rsp), %al
movb %al, 0xc(%rsp)
addq $0x58, %rdi
movzwl 0x1e(%rsp), %eax
subl $0xfe00, %eax           # imm = 0xFE00
movslq %eax, %rsi
callq 0x40f0
movb 0xc(%rsp), %cl
movb %cl, (%rax)
jmp 0xef20
movzwl 0x1e(%rsp), %eax
cmpl $0xff00, %eax           # imm = 0xFF00
jl 0xea08
movzwl 0x1e(%rsp), %eax
cmpl $0xff7f, %eax           # imm = 0xFF7F
jle 0xea18
movzwl 0x1e(%rsp), %eax
cmpl $0xffff, %eax           # imm = 0xFFFF
jne 0xeed8
movzwl 0x1e(%rsp), %eax
movl %eax, 0x8(%rsp)
subl $0xff00, %eax           # imm = 0xFF00
je 0xeb63
jmp 0xea2e
movl 0x8(%rsp), %eax
subl $0xff04, %eax           # imm = 0xFF04
je 0xeb7b
jmp 0xea3f
movl 0x8(%rsp), %eax
subl $0xff05, %eax           # imm = 0xFF05
je 0xeb8e
jmp 0xea50
movl 0x8(%rsp), %eax
subl $0xff06, %eax           # imm = 0xFF06
je 0xeba3
jmp 0xea61
movl 0x8(%rsp), %eax
subl $0xff07, %eax           # imm = 0xFF07
je 0xebb8
jmp 0xea72
movl 0x8(%rsp), %eax
subl $0xff0f, %eax           # imm = 0xFF0F
je 0xee84
jmp 0xea83
movl 0x8(%rsp), %eax
subl $0xff40, %eax           # imm = 0xFF40
je 0xebd4
jmp 0xea94
movl 0x8(%rsp), %eax
subl $0xff41, %eax           # imm = 0xFF41
je 0xebe5
jmp 0xeaa5
movl 0x8(%rsp), %eax
subl $0xff42, %eax           # imm = 0xFF42
je 0xec09
jmp 0xeab6
movl 0x8(%rsp), %eax
subl $0xff43, %eax           # imm = 0xFF43
je 0xec1a
jmp 0xeac7
movl 0x8(%rsp), %eax
subl $0xff45, %eax           # imm = 0xFF45
je 0xec2b
jmp 0xead8
movl 0x8(%rsp), %eax
subl $0xff46, %eax           # imm = 0xFF46
je 0xec3c
jmp 0xeae9
movl 0x8(%rsp), %eax
subl $0xff47, %eax           # imm = 0xFF47
je 0xec8a
jmp 0xeafa
movl 0x8(%rsp), %eax
subl $0xff48, %eax           # imm = 0xFF48
je 0xec9b
jmp 0xeb0b
movl 0x8(%rsp), %eax
subl $0xff49, %eax           # imm = 0xFF49
je 0xecac
jmp 0xeb1c
movl 0x8(%rsp), %eax
subl $0xff4a, %eax           # imm = 0xFF4A
je 0xecbd
jmp 0xeb2d
movl 0x8(%rsp), %eax
subl $0xff4b, %eax           # imm = 0xFF4B
je 0xecce
jmp 0xeb3e
movl 0x8(%rsp), %eax
subl $0xff50, %eax           # imm = 0xFF50
je 0xecdf
jmp 0xeb4f
movl 0x8(%rsp), %eax
subl $0xffff, %eax           # imm = 0xFFFF
je 0xee61
jmp 0xeead
movq 0x10(%rsp), %rax
movq 0x8(%rax), %rdi
movzbl 0x1d(%rsp), %esi
callq 0xc590
jmp 0xeed6
movq 0x10(%rsp), %rax
movq 0x10(%rax), %rax
movw $0x0, (%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movq 0x10(%rax), %rax
movb %cl, 0x2(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movq 0x10(%rax), %rax
movb %cl, 0x3(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movzbl 0x1d(%rsp), %ecx
orl $0xf8, %ecx
movq 0x10(%rax), %rax
movb %cl, 0x4(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x18(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movzbl 0x19(%rax), %ecx
andl $0x7, %ecx
movzbl 0x1d(%rsp), %edx
andl $0x78, %edx
orl %edx, %ecx
orl $0x80, %ecx
movb %cl, 0x19(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x1a(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x1b(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x1d(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rdi
movb 0x1d(%rsp), %al
movb %al, 0x7(%rsp)
addq $0x70, %rdi
movl $0x46, %esi
callq 0x40f0
movb 0x7(%rsp), %dl
movq %rax, %rcx
movq 0x10(%rsp), %rax
movb %dl, (%rcx)
movzbl 0x26(%rax), %eax
cmpl $0xa0, %eax
jle 0xec85
movq 0x10(%rsp), %rax
movzbl 0x1d(%rsp), %ecx
shll $0x8, %ecx
movw %cx, 0x24(%rax)
movb $0x0, 0x26(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x1e(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x1f(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x20(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x21(%rax)
jmp 0xeed6
movq 0x10(%rsp), %rax
movb 0x1d(%rsp), %cl
movb %cl, 0x22(%rax)
jmp 0xeed6
movzbl 0x1d(%rsp), %eax
cmpl $0x1, %eax
jne 0xee5f
movq 0x10(%rsp), %rax
testb $0x1, 0x23(%rax)
je 0xee5f
movq 0x10(%rsp), %rdi
movb $0x0, 0x23(%rdi)
movl $0xff10, %esi           # imm = 0xFF10
movl $0x80, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff11, %esi           # imm = 0xFF11
movl $0xbf, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff12, %esi           # imm = 0xFF12
movl $0xf3, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff14, %esi           # imm = 0xFF14
movl $0xbf, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff16, %esi           # imm = 0xFF16
movl $0x3f, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff17, %esi           # imm = 0xFF17
xorl %edx, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff19, %esi           # imm = 0xFF19
movl $0xbf, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff1a, %esi           # imm = 0xFF1A
movl $0x7f, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff1b, %esi           # imm = 0xFF1B
movl $0xff, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff1c, %esi           # imm = 0xFF1C
movl $0x9f, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff1e, %esi           # imm = 0xFF1E
movl $0xbf, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff20, %esi           # imm = 0xFF20
movl $0xff, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff21, %esi           # imm = 0xFF21
xorl %edx, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff22, %esi           # imm = 0xFF22
xorl %edx, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff23, %esi           # imm = 0xFF23
movl $0xbf, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff24, %esi           # imm = 0xFF24
movl $0x77, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff25, %esi           # imm = 0xFF25
movl $0xf3, %edx
callq 0xe840
movq 0x10(%rsp), %rdi
movl $0xff26, %esi           # imm = 0xFF26
movl $0xf1, %edx
callq 0xe840
jmp 0xeed6
movq 0x10(%rsp), %rdi
movb 0x1d(%rsp), %al
movb %al, 0x6(%rsp)
addq $0x70, %rdi
movl $0xff, %esi
callq 0x40f0
movb 0x6(%rsp), %cl
movb %cl, (%rax)
jmp 0xeed6
movq 0x10(%rsp), %rdi
movzbl 0x1d(%rsp), %eax
orl $0xe0, %eax
movb %al, 0x5(%rsp)
addq $0x70, %rdi
movl $0xf, %esi
callq 0x40f0
movb 0x5(%rsp), %cl
movb %cl, (%rax)
jmp 0xeed6
movq 0x10(%rsp), %rdi
movb 0x1d(%rsp), %al
movb %al, 0x4(%rsp)
addq $0x70, %rdi
movzwl 0x1e(%rsp), %eax
subl $0xff00, %eax           # imm = 0xFF00
movslq %eax, %rsi
callq 0x40f0
movb 0x4(%rsp), %cl
movb %cl, (%rax)
jmp 0xef1e
movzwl 0x1e(%rsp), %eax
cmpl $0xff80, %eax           # imm = 0xFF80
jl 0xef1c
movzwl 0x1e(%rsp), %eax
cmpl $0xfffe, %eax           # imm = 0xFFFE
jg 0xef1c
movq 0x10(%rsp), %rdi
movb 0x1d(%rsp), %al
movb %al, 0x3(%rsp)
addq $0x88, %rdi
movzwl 0x1e(%rsp), %eax
subl $0xff80, %eax           # imm = 0xFF80
movslq %eax, %rsi
callq 0x40f0
movb 0x3(%rsp), %cl
movb %cl, (%rax)
jmp 0xef1e
jmp 0xef20
jmp 0xef22
jmp 0xef24
jmp 0xef26
jmp 0xef28
jmp 0xef2a
addq $0x28, %rsp
retq
nop