<commit_before>'use strict';

const step = require('debug')('lcd:step');
const mode = require('debug')('lcd:mode');
const line = require('debug')('lcd:line');
const { LCDSTAT, CURLINE, CMPLINE } = require('./registers');
const { INT_40, INT_48 } = require('./interrupts');

const MAX_CYCLES = 456;


class Lcd {
    constructor (mmu, gpu) {
        this._mmu = mmu;
        this._gpu = gpu;

        // Registers

        this._stat = 0;
        this._ly = 0;
        this._lyc = 0;

        // Timer

        this._t = MAX_CYCLES;
    }

    step (cycles) {
        step('%d', cycles);

        this._t -= cycles;

        // LCDC Status

        let stat = 0;

        /**
         * Mode Flag
         *
         * Mode 0 is present between 201-207 clks, 2 about 77-83 clks, and
         * 3 about 169-175 clks. A complete cycle through these states takes
         * 456 clks. VBlank lasts 4560 clks. A complete screen refresh
         * occurs every 70224 clks.
         */
        const ly = this._ly;
        if (ly < 144) {
            if (this._t > 376) stat |= 2;
            else if (this._t > 204) stat |= 3;
        }
        else if (ly < 154) stat |= 1;

        const pre = this._stat & 3;
        const cur = stat & 3;

        if (pre != cur) switch (cur) {
            case 1: this._stat |= 1 << 4;
            case 2: this._stat |= 1 << 5; break;
            case 0: this._stat |= 1 << 3; break;
        }

        mode('%d; ly=%d', cur, ly);

        if (this._t > 0) {
            if (pre != cur) this._mmu.if |= INT_48;
            return;
        }

        // Line

        line('%d', ly);

        if (ly == 144) this._mmu.if |= INT_40;

        // Coincidence line

        if (ly == this._lyc) {
            this._mmu.if |= INT_48;
            this._stat |= 1 << 2;
        }

        if (ly < 144) this._gpu.drawLine(ly);

        // Next Scanline

        this._ly = ly < 153 ? ly + 1 : 0;

        if (ly < 153) this._t += MAX_CYCLES;
        else this._t = MAX_CYCLES;
    }

    readByte (addr) {
        switch (addr) {
            case LCDSTAT: return this._stat;
            case CURLINE: return this._ly;
            case CMPLINE: return this._lyc;
        }

        throw new Error(`unmapped address 0x${addr.toString(16)}`);
    }

    writeByte (addr, val) {
        switch (addr) {
            case LCDSTAT: return this._stat = val;
            case CURLINE: return this._ly = val;
            case CMPLINE: return this._lyc = val;
        }
<commit_msg>mask and protect read-only registers<commit_after>'use strict';

const step = require('debug')('lcd:step');
const mode = require('debug')('lcd:mode');
const line = require('debug')('lcd:line');
const { LCDSTAT, CURLINE, CMPLINE } = require('./registers');
const { INT_40, INT_48 } = require('./interrupts');

const MAX_CYCLES = 456;


class Lcd {
    constructor (mmu, gpu) {
        this._mmu = mmu;
        this._gpu = gpu;

        // Registers

        this._stat = 0;
        this._ly = 0;
        this._lyc = 0;

        // Timer

        this._t = MAX_CYCLES;
    }

    step (cycles) {
        step('%d', cycles);

        this._t -= cycles;

        // LCDC Status

        let stat = 0;

        /**
         * Mode Flag
         *
         * Mode 0 is present between 201-207 clks, 2 about 77-83 clks, and
         * 3 about 169-175 clks. A complete cycle through these states takes
         * 456 clks. VBlank lasts 4560 clks. A complete screen refresh
         * occurs every 70224 clks.
         */
        const ly = this._ly;
        if (ly < 144) {
            if (this._t > 376) stat |= 2;
            else if (this._t > 204) stat |= 3;
        }
        else if (ly < 154) stat |= 1;

        const pre = this._stat & 3;
        const cur = stat & 3;

        if (pre != cur) switch (cur) {
            case 1: this._stat |= 1 << 4;
            case 2: this._stat |= 1 << 5; break;
            case 0: this._stat |= 1 << 3; break;
        }

        mode('%d; ly=%d', cur, ly);

        if (this._t > 0) {
            if (pre != cur) this._mmu.if |= INT_48;
            return;
        }

        // Line

        line('%d', ly);

        if (ly == 144) this._mmu.if |= INT_40;

        // Coincidence line

        if (ly == this._lyc) {
            this._mmu.if |= INT_48;
            this._stat |= 1 << 2;
        }

        if (ly < 144) this._gpu.drawLine(ly);

        // Next Scanline

        this._ly = ly < 153 ? ly + 1 : 0;

        if (ly < 153) this._t += MAX_CYCLES;
        else this._t = MAX_CYCLES;
    }

    readByte (addr) {
        switch (addr) {
            case LCDSTAT: return this._stat;
            case CURLINE: return this._ly;
            case CMPLINE: return this._lyc;
        }

        throw new Error(`unmapped address 0x${addr.toString(16)}`);
    }

    writeByte (addr, val) {
        switch (addr) {
            case LCDSTAT: return this._stat |= val & 0x78;
            case CURLINE: return this._ly;
            case CMPLINE: return this._lyc = val;
        }

{'fraction_non_alphanumeric': 0.13479561316051844, 'fraction_numerical': 0.038085742771684944, 'mean_word_length': 1.4758144126357355, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4168599', 'n_tokens_mistral': 1831, 'n_tokens_neox': 1590, 'n_words': 478}