private void renderBackground(int line) {
        int dstX = (fineX ^ 7) - 7;
        int tileCount = 0;
        int tileIndex = 0;

        int vtile = ((address & 0x3E0) >> 5) & 0x1F;
        int fineY = (address & 0x7000) >> 12;
        int pattern = 0x0;
        if ((control & R_CONTROL_BG_PATTERN) != 0)
            pattern = 0x1000;

        while (tileCount < 34) {
            int htile = address & 0x1F;
            int nametbl = (((address & 0xC00) >> 10) * 0x400);
            int pixelA, pixelB;
            int colorBits;
            int tileNum = vtile * 32 + htile;

            if (tileNum < 960) {

                tileIndex = readFromNametable(nametbl + tileNum) & 0xFF;
                colorBits = readFromNametable(nametbl + 0x3C0 + attributeAddr[tileNum]);

                pixelA = bus.readChr(pattern + (tileIndex * 16) + fineY) & 0xFF;
                pixelB = bus.readChr(pattern + (tileIndex * 16) + fineY + 8) & 0xFF;

                colorBits = ((colorBits >> attributeBit[tileNum]) & 3) << 2;

                for (int px = 0; px < 8; px++) {
                    int color;

                    pixelA = ROL(pixelA);
                    pixelB = ROL(pixelB);

                    if (dstX >= 0 && dstX < 256) {
                        color = (pixelA & 1) | ((pixelB & 1) << 1);
                        color &= 0x3F;
                        if (color != 0) {
                            color |= colorBits;
                        }
                        int cindex = bgPalette[color & 0xF];
                        framebuffer[line * WIDTH + dstX] = nesColors[cindex & 0x3F];
                    }
                    ++dstX;
                }
            }
            clockHTile();
            ++tileCount;
        }
        clockFineY();
    }