// File: NGageMegaman[P]NEScutre/src/ppu.cpp
// Function: Ppu::draw(int)
void Ppu::draw(int n_scanline) {
    //Select what events the window will listen to
    //XEvent ev;
    unsigned int nametable;
    unsigned int idx = 0;
    unsigned int attribute_addr = 0;
    unsigned char attribute;
    unsigned int line_addr, h_offset;
    unsigned int nt_off;
    unsigned int patterntable;
    int pos_x, pos_y, sc_off_x, sc_off_y;
    //int a = XNextEvent(di, &ev);
    //if (ev.type == Expose) {
    //BG enable
    if ((mem_ppu->PPUMASK >> 3)&1) {
	if ((n_scanline & 0x7) == 0) {
	    int i = n_scanline/8;
	    //Leftmost tiles
	    if (i > 0 || ((mem_ppu->PPUMASK >> 1)&1)) {
		for (int j = 0; j<32; ++j) {
	    	    //TILE
	    	    for (int i2 = 0; i2<8; ++i2) {
			for (int j2 = 0; j2<8; ++j2) {

			    //Compute the scrolling tile offsets
			    sc_off_y = mem_ppu->PPUSCROLL & 0x00ff;
			    sc_off_x = ((mem_ppu->PPUSCROLL & 0xff00)>>8) & 0x00ff;

			    //Compute which nametable we use
			    nt_off = (mem_ppu->PPUCTRL & 3);

			    //Compute the position
			    pos_x = (j*8)+j2 - sc_off_x;
			    if (pos_x < 0) {
				pos_x += 32*8;
				nt_off = (nt_off & 2) | ((nt_off+1) & 1);
			    }
			    pos_y = (i*8)+i2 - sc_off_y;
			    if (pos_y < 0) {
				pos_y += 30*8;
				nt_off = ((nt_off+2) & 2) | (nt_off & 1);
			    }

			    nametable = 0x2000 + (nt_off * 0x0400);

			    //Compute which pattern table we use
			    patterntable = (mem_ppu->PPUCTRL >> 4) & 1;
			    //Fetch the index of the bg tile
			    idx = (mem_ppu->ram[nametable+(i*32)+j]);
			    //If we use the second pt, we add 256 to the index
			    if (patterntable) 
				idx += 256;
			    //Each pattern is 16-byte wide. i2 is the vertical offset
			    line_addr = (idx * 16) + i2;
			    //j2 is the horizontal offset. We start from the MSB
			    h_offset = (7-j2);

            	    	    //Compute the bitplane

            	    	    /*
            	    	    Each tile is formed by two bitplanes. The first one
            	    	    is followed by the second one. We fetch the line_addr byte,
            	    	    which contains the first bitplane of a given line, and the
            	    	    line_addr+8 byte, which contains the second one. Using
            	    	    h_offset we get the particular bit of the line that we want
            	    	    */

	    	    	    unsigned char bitplane = 
	    	    	     (((mem_ppu->ram[line_addr]  )>>h_offset)&1) |
	    	    	    ((((mem_ppu->ram[line_addr+8])>>h_offset)&1)<<1);

            	    	    //Compute the attribute address of the tile
            	    	    //TODO: this can be done outside the tile render loop
	    	    	    attribute_addr = nametable + 0x03c0;
            	    	    
            	    	    /*
            	    	    Each attribute contains 4 pallette indexes corresponding to
            	    	    a 2x2 tile portion of the screen. They are arranged, from
            	    	    MSB to LSB as such:

            	    	    bottom right, bottom left, top right, top left
            	    	         7,6           5,4        3,2       1,0

            	    	    That means that each pattern contains the pallette of
            	    	    two different rows and two different columns. If the
            	    	    row is odd, we shift the attribute 4 bits right, and if the
            	    	    column is odd, we shift the attribute 2 bits right. This
            	    	    way we get the correct pallette index on the lower 2 bits.
            	    	    */

	    	    	    //Determine the attribute address
	    	            attribute_addr = attribute_addr + (i/4)*8;
	    	            attribute_addr = attribute_addr + (j/4);
	    	    	    //Fetch the attribute byte
	    	            attribute = mem_ppu->ram[attribute_addr];
	    	    	    //Arrange the lower 2 bits with the correct pallette index
	    	            if ((i & 3) > 1) {
	    	                attribute = attribute >> 4;
	    	            }
	    	            if ((j & 3) > 1) {
	    	                attribute = attribute >> 2;
	    	            }
	    	    	    //We compute the final pallette index with the bitplane value
	    	            attribute = ((attribute << 2) | bitplane) & 0x000f;
			    if (bitplane == 0) attribute = 0;
	    	    	    //We fetch the color value
	    	            unsigned char color = mem_ppu->ram[0x3f00 + attribute];
			    int position = (pos_y*256)+pos_x;
			    if (position < 61440)
				mem_ppu->vram[position] = colors[color];
			}
		    }
	    	}
	    }
	}
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x60(%rbp)
movl $0x0, -0x14(%rbp)
movl $0x0, -0x18(%rbp)
movq 0x8(%rax), %rax
movzbl 0x3c019(%rax), %eax
sarl $0x3, %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x6808
movl -0xc(%rbp), %eax
andl $0x7, %eax
cmpl $0x0, %eax
jne 0x6806
movl -0xc(%rbp), %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, -0x40(%rbp)
cmpl $0x0, -0x40(%rbp)
jg 0x655b
movq -0x60(%rbp), %rax
movq 0x8(%rax), %rax
movzbl 0x3c019(%rax), %eax
sarl %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x6804
movl $0x0, -0x44(%rbp)
cmpl $0x20, -0x44(%rbp)
jge 0x6802
movl $0x0, -0x48(%rbp)
cmpl $0x8, -0x48(%rbp)
jge 0x67f2
movl $0x0, -0x4c(%rbp)
cmpl $0x8, -0x4c(%rbp)
jge 0x67e2
movq -0x60(%rbp), %rax
movq 0x8(%rax), %rcx
movzwl 0x3c01a(%rcx), %ecx
andl $0xff, %ecx
movl %ecx, -0x3c(%rbp)
movq 0x8(%rax), %rcx
movzwl 0x3c01a(%rcx), %ecx
andl $0xff00, %ecx           # imm = 0xFF00
sarl $0x8, %ecx
andl $0xff, %ecx
movl %ecx, -0x38(%rbp)
movq 0x8(%rax), %rax
movzbl 0x3c010(%rax), %eax
andl $0x3, %eax
movl %eax, -0x28(%rbp)
movl -0x44(%rbp), %eax
shll $0x3, %eax
addl -0x4c(%rbp), %eax
subl -0x38(%rbp), %eax
movl %eax, -0x30(%rbp)
cmpl $0x0, -0x30(%rbp)
jge 0x6608
movl -0x30(%rbp), %eax
addl $0x100, %eax            # imm = 0x100
movl %eax, -0x30(%rbp)
movl -0x28(%rbp), %eax
andl $0x2, %eax
movl -0x28(%rbp), %ecx
addl $0x1, %ecx
andl $0x1, %ecx
orl %ecx, %eax
movl %eax, -0x28(%rbp)
movl -0x40(%rbp), %eax
shll $0x3, %eax
addl -0x48(%rbp), %eax
subl -0x3c(%rbp), %eax
movl %eax, -0x34(%rbp)
cmpl $0x0, -0x34(%rbp)
jge 0x663c
movl -0x34(%rbp), %eax
addl $0xf0, %eax
movl %eax, -0x34(%rbp)
movl -0x28(%rbp), %eax
addl $0x2, %eax
andl $0x2, %eax
movl -0x28(%rbp), %ecx
andl $0x1, %ecx
orl %ecx, %eax
movl %eax, -0x28(%rbp)
movq -0x60(%rbp), %rax
movl -0x28(%rbp), %ecx
shll $0xa, %ecx
addl $0x2000, %ecx           # imm = 0x2000
movl %ecx, -0x10(%rbp)
movq 0x8(%rax), %rcx
movzbl 0x3c010(%rcx), %ecx
sarl $0x4, %ecx
andl $0x1, %ecx
movl %ecx, -0x2c(%rbp)
movq 0x8(%rax), %rax
movq (%rax), %rax
movl -0x10(%rbp), %ecx
movl -0x40(%rbp), %edx
shll $0x5, %edx
addl %edx, %ecx
addl -0x44(%rbp), %ecx
movl %ecx, %ecx
movzbl (%rax,%rcx), %eax
movl %eax, -0x14(%rbp)
cmpl $0x0, -0x2c(%rbp)
je 0x6692
movl -0x14(%rbp), %eax
addl $0x100, %eax            # imm = 0x100
movl %eax, -0x14(%rbp)
movq -0x60(%rbp), %rax
movl -0x14(%rbp), %ecx
shll $0x4, %ecx
addl -0x48(%rbp), %ecx
movl %ecx, -0x20(%rbp)
movl $0x7, %ecx
subl -0x4c(%rbp), %ecx
movl %ecx, -0x24(%rbp)
movq 0x8(%rax), %rax
movq (%rax), %rax
movl -0x20(%rbp), %ecx
movzbl (%rax,%rcx), %eax
movl -0x24(%rbp), %ecx
sarl %cl, %eax
movq -0x60(%rbp), %rcx
andl $0x1, %eax
movq 0x8(%rcx), %rcx
movq (%rcx), %rcx
movl -0x20(%rbp), %edx
addl $0x8, %edx
movl %edx, %edx
movzbl (%rcx,%rdx), %edx
movl -0x24(%rbp), %ecx
sarl %cl, %edx
movl %edx, %ecx
andl $0x1, %ecx
shll %ecx
orl %ecx, %eax
movb %al, -0x4d(%rbp)
movl -0x10(%rbp), %eax
addl $0x3c0, %eax            # imm = 0x3C0
movl %eax, -0x18(%rbp)
movl -0x18(%rbp), %eax
movl %eax, -0x64(%rbp)
movl -0x40(%rbp), %eax
movl $0x4, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movl -0x64(%rbp), %eax
shll $0x3, %ecx
addl %ecx, %eax
movl %eax, -0x18(%rbp)
movl -0x18(%rbp), %ecx
movl -0x44(%rbp), %eax
movl $0x4, %esi
cltd
idivl %esi
movl %eax, %edx
movq -0x60(%rbp), %rax
addl %edx, %ecx
movl %ecx, -0x18(%rbp)
movq 0x8(%rax), %rax
movq (%rax), %rax
movl -0x18(%rbp), %ecx
movb (%rax,%rcx), %al
movb %al, -0x19(%rbp)
movl -0x40(%rbp), %eax
andl $0x3, %eax
cmpl $0x1, %eax
jle 0x6752
movzbl -0x19(%rbp), %eax
sarl $0x4, %eax
movb %al, -0x19(%rbp)
movl -0x44(%rbp), %eax
andl $0x3, %eax
cmpl $0x1, %eax
jle 0x6767
movzbl -0x19(%rbp), %eax
sarl $0x2, %eax
movb %al, -0x19(%rbp)
movzbl -0x19(%rbp), %eax
shll $0x2, %eax
movzbl -0x4d(%rbp), %ecx
orl %ecx, %eax
andl $0xf, %eax
movb %al, -0x19(%rbp)
movzbl -0x4d(%rbp), %eax
cmpl $0x0, %eax
jne 0x6787
movb $0x0, -0x19(%rbp)
movq -0x60(%rbp), %rax
movq 0x8(%rax), %rax
movq (%rax), %rax
movzbl -0x19(%rbp), %ecx
addl $0x3f00, %ecx           # imm = 0x3F00
movslq %ecx, %rcx
movb (%rax,%rcx), %al
movb %al, -0x4e(%rbp)
movl -0x34(%rbp), %eax
shll $0x8, %eax
addl -0x30(%rbp), %eax
movl %eax, -0x54(%rbp)
cmpl $0xf000, -0x54(%rbp)    # imm = 0xF000
jge 0x67d2
movq -0x60(%rbp), %rax
movzbl -0x4e(%rbp), %ecx
movl 0x38(%rax,%rcx,4), %edx
movq 0x8(%rax), %rax
movslq -0x54(%rbp), %rcx
movl %edx, 0x10(%rax,%rcx,4)
jmp 0x67d4
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x6584
jmp 0x67e4
movl -0x48(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x48(%rbp)
jmp 0x6573
jmp 0x67f4
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
jmp 0x6562
jmp 0x6804
jmp 0x6806
jmp 0x6808
popq %rbp
retq
nopw (%rax,%rax)