Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ファミコンエミュレータの創り方

bokuweb
September 07, 2018
43k

 ファミコンエミュレータの創り方

bokuweb

September 07, 2018
Tweet

Transcript

  1. CVJMEFSTDPOUPLZP
    ϑΝϛίϯΤϛϡϨʔλ
    ͷ૑Γํ
    !CPLVXFC

    View full-size slide

  2. !CPLVXFC
    IUUQCMPHCPLVXFCNF
    w ૊ΈࠐΈϋʔυιϑτ΢ΣΞΤϯδχΞ
    w 8FCϑϩϯτΤϯυΤϯδχΞ
    w ࢁ͔Β߱Γ͖ͯ·ͨ͠
    CPLVXFC
    ࣗݾ঺հ

    View full-size slide

  3. ͍͞͠ΐʹ
    !3VTU8FC"TTFNCMZ XJUIFNTDSJQUFO
    Ͱ
    ϑΝϛίϯΤϛϡϨʔλΛ࣮૷ͯ͠Έͨ࿩͠Λ͢ΔηογϣϯͰ͢
    !3VTU8FC"TTFNCMZͷجૅ΍ৄࡉʹ͸͋·Γ৮Ε·ͤΜ
    !ϑΝϛίϯͷϋʔυ΢ΣΞ΍੍໿ɺͦͷΤϛϡϨʔγϣϯํ๏
    Λॏ఺తʹ͓࿩͢Δͭ΋ΓͰ͢

    View full-size slide

  4. 2ϑΝϛίϯͷ࣮ػͰ
    ༡Μͩ͜ͱ͋Δਓ"

    View full-size slide

  5. %&.0
    IUUQTHJUIVCDPNCPLVXFCSVTUZOFT

    View full-size slide

  6. $16 31" 3*$0)੡
    CJU.)[
    116 ϐΫνϟʔϓϩηοαϢχοτ31$
    30. ࠷େϓϩάϥϜ30.,J#ΩϟϥΫλ30.,J#
    83". ϫʔΩϯά3".,J#
    73". ϏσΦ3".,J#
    ࠷େൃ৭਺ ৭
    ը໘ղ૾౓ ºϐΫηϧ
    α΢ϯυ ۣܗ೾ɺࡾ֯೾ɺϊΠζɺ%1$.
    ίϯτϩʔϥ ˢɺˣɺˡɺˠɺ"ɺ#ɺ45"35ɺ4&-&$5
    ϑΝϛίϯͷεϖοΫ

    View full-size slide

  7. $16
    31"
    116
    31$
    73".
    ,J#
    83".
    ,J#
    #6'
    Χηοτ
    .)[
    .)[
    /.*
    CJU116CVT
    CJU$16CVT
    "16
    ϑΝϛίϯ
    σΟεϓϨΠ
    α΢ϯυ
    ίϯτϩʔϥ
    ϑΝϛίϯͷϒϩοΫਤ

    View full-size slide

  8. ΤϛϡϨʔλΛ࡞Δʹ͸
    ͜ΕΒͷσόΠεΛҰͭҰͭ
    ࣮૷͍ͯ͘͠ඞཁ͕͋Δ

    View full-size slide

  9. ·ͣ͸ϑΝϛίϯͷΧηοτ

    View full-size slide

  10. 2த਎͕Ͳ͏ͳͬͯΔ͔
    ஌ͬͯ·͔͢ʁ

    View full-size slide

  11. ϓϩάϥϜ30.
    "த਎͸͜͏ͳ͍ͬͯΔ

    View full-size slide

  12. "த਎͸͜͏ͳ͍ͬͯΔ
    ΩϟϥΫλʔ30.

    View full-size slide

  13. ຊମͱͷ઀ଓίωΫλ
    "த਎͸͜͏ͳ͍ͬͯΔ

    View full-size slide

  14. -------
    GND -- |01 31| -- +5V
    CPU A11 -> |02 32| <- M2
    CPU A10 -> |03 33| <- CPU A12
    CPU A9 -> |04 34| <- CPU A13
    CPU A8 -> |05 35| <- CPU A14
    CPU A7 -> |06 36| <> CPU D7
    CPU A6 -> |07 37| <> CPU D6
    CPU A5 -> |08 38| <> CPU D5
    CPU A4 -> |09 39| <> CPU D4
    CPU A3 -> |10 40| <> CPU D3
    CPU A2 -> |11 41| <> CPU D2
    CPU A1 -> |12 42| <> CPU D1
    CPU A0 -> |13 43| <> CPU D0
    CPU R/W -> |14 44| <- /ROMSEL (/A15 + /M2)
    /IRQ <- |15 45| <- Audio from 2A03
    GND -- |16 46| -> Audio to RF
    PPU /RD -> |17 47| <- PPU /WR
    CIRAM A10 <- |18 48| -> CIRAM /CE
    PPU A6 -> |19 49| <- PPU /A13
    PPU A5 -> |20 50| <- PPU A7
    PPU A4 -> |21 51| <- PPU A8
    PPU A3 -> |22 52| <- PPU A9
    PPU A2 -> |23 53| <- PPU A10
    PPU A1 -> |24 54| <- PPU A11
    PPU A0 -> |25 55| <- PPU A12
    PPU D0 <> |26 56| <- PPU A13
    PPU D1 <> |27 57| <> PPU D7
    PPU D2 <> |28 58| <> PPU D6
    PPU D3 <> |29 59| <> PPU D5
    +5V -- |30 60| <> PPU D4
    -------
    ΧηοτͷίωΫλϐϯ഑ྻΛݟΔͱ
    $16116ͷCJUόε৴߸͕ͦΕͧΕ઀ଓ͞Ε͍ͯΔ
    Χηοτͷϐϯ഑ྻ
    $16ͷόε৴߸
    116ͷόε৴߸

    View full-size slide

  15. ΩϟϥΫλʔ
    30.
    116 $16
    ϑΝϛίϯຊମ
    ϓϩάϥϜ
    30.
    Χηοτ
    $16όεΛհͯ͠
    Ϧʔυ͞ΕΔ
    116όεΛհͯ͠
    Ϧʔυ͞ΕΔ
    Χηοτͱຊମͱͷόε઀ଓ

    View full-size slide

  16. ϓϩάϥϜ30.ͱ͸

    View full-size slide

  17. ήʔϜϓϩάϥϜ͕֨ೲ͞Εͨ30.
    $16͸ϓϩάϥϜ30.͔Β໋ྩϑΣονͯ͠ϓϩάϥϜ
    Λ࣮ߦ͢Δ
    void main()
    {
    char i;
    *(char*)0x2000 = 0x00;
    *(char*)0x2001 = 0x00;
    ͜Μͳͷ͕
    "'''"ʜ
    ͜Μͳײ͡Ͱ٧·ͬͯΔ
    ϓϩάϥϜ30.ͱ͸

    View full-size slide

  18. ΩϟϥΫλʔ30.ͱ͸

    View full-size slide

  19. ºͷήʔϜը૾͕֨ೲ͞Εͨ30.ʢ࠷େ,J#ʣ
    എܠͱΩϟϥΫλʔͦΕͧΕͷσʔλ͕٧·ͬͯΔ
    116͕ΩϟϥΫλʔ30.͔Βը૾σʔλΛಡΜͰ
    ը໘্ʹ഑ஔ͢Δ
    ΩϟϥΫλʔ30.ͱ͸

    View full-size slide

  20. ՄࢹԽͯ͠ΈΔͱ

    View full-size slide

  21. ҎԼ͸ઌఔͷσϞʮGBMMJOHʯͷΩϟϥΫλʔ30.ͷத਎
    ΩϟϥΫλʔ30.ͱ͸

    View full-size slide

  22. ̔#ZUFº#ZUFͰºαΠζͷը૾͕දݱ͞ΕΔ
    ҎԼ͸30.಺ͷεϓϥΠτΠϯσοΫε͕ϋʔτϚʔΫͩͬͨ৔߹ͷྫ
    "EESFTTT %BUB
    Y Y
    Y Y'
    Y Y''
    Y Y''
    Y Y''
    Y Y&
    Y Y$
    Y Y
    "EESFTTT %BUB
    Y Y
    Y Y'
    Y" Y#'
    Y# Y#'
    Y$ Y''
    Y% Y&
    Y& Y$
    Y' Y

























    ΩϟϥΫλʔ30.ͷσʔλ

    View full-size slide

  23. ΤϛϡϨʔλͰ͸͜ΕΒͷ৘ใΛ
    Ͳ͏औΓѻ͑͹͍͍͔

    View full-size slide

  24. J/&4ϑΥʔϚοτ

    View full-size slide

  25. $POTUBOU&" /&4GPMMPXFECZ.4%04FOEPGpMF

    4J[FPG13(30.JO,#VOJUT
    4J[FPG$)330.JO,#VOJUT 7BMVFNFBOTUIFCPBSEVTFT$)33".

    'MBHT
    'MBHT
    4J[FPG13(3".JO,#VOJUT 7BMVFJOGFST,#GPSDPNQBUJCJMJUZTFF13(3".DJSDVJU

    'MBHT
    'MBHT VOPGpDJBM

    ;FSPpMMFE
    #ZUF ,J#ZUF#MPDLTJ[F
    J/&4
    IFBEFS
    J/&4
    IFBEFS ϓϩάϥϜ30.
    ϓϩάϥϜ30. ΩϟϥΫλʔ30.
    ,J#ZUF#MPDLTJ[F
    J/&4IFBEFS
    ֦ுྖҬ
    J/&4ϑΥʔϚοτͷத਎
    #ZIFBEFSͷ#ZUFʹ
    ֤30.ͷϒϩοΫαΠζ͕
    ֨ೲ͞Ε͍ͯΔ

    View full-size slide

  26. ·ͣ͸OFTΛಡΜͰղੳͯ͠
    ֤30.Λ੾Γग़ͯ͠΍Δඞཁ͕͋Δ

    View full-size slide

  27. XBTN͔ΒOFTϑΝΠϧΛಡΉͷ͸େม
    ࠓճ͸+BWB4DSJQUଆͰOFTϑΝΠϧΛ
    GFUDIͯ͠3VTU XBTN
    ଆʹҾ͖౉͢͜ͱʹͨ͠

    View full-size slide

  28. const run = Module.cwrap("run", null, ["number", "number"]);
    const res = await fetch("./PATH_TO_NES_FILE.nes");
    const arrayBuf = await res.arrayBuffer();
    const nes = new Uint8Array(arrayBuf);
    const size = nes.byteLength;
    const ptr = Module._malloc(size);
    const buf = new Uint8Array(Module.HEAPU8.buffer, ptr, size);
    buf.set(nes);
    run(size, buf.byteOffset);
    +BWB4DSJQUଆͷॳظԽॲཧ
    3VTUଆͷؔ਺Λ+4
    ͔Βݺ΂ΔΑ͏ʹ ͜Ε͸Ҿ਺

    View full-size slide

  29. const run = Module.cwrap("run", null, ["number", "number"]);
    const res = await fetch("./PATH_TO_NES_FILE.nes");
    const arrayBuf = await res.arrayBuffer();
    const nes = new Uint8Array(arrayBuf);
    const size = nes.byteLength;
    const ptr = Module._malloc(size);
    const buf = new Uint8Array(Module.HEAPU8.buffer, ptr, size);
    buf.set(nes);
    run(size, buf.byteOffset);
    +BWB4DSJQUଆͷॳظԽॲཧ
    OFTϑΝΠϧΛϑΣον
    ͯ͠"SSBZ#VGGFSʹม׵

    View full-size slide

  30. const run = Module.cwrap("run", null, ["number", "number"]);
    const res = await fetch("./PATH_TO_NES_FILE.nes");
    const arrayBuf = await res.arrayBuffer();
    const nes = new Uint8Array(arrayBuf);
    const size = nes.byteLength;
    const ptr = Module._malloc(size);
    const buf = new Uint8Array(Module.HEAPU8.buffer, ptr, size);
    buf.set(nes);
    run(size, buf.byteOffset);
    +BWB4DSJQUଆͷॳظԽॲཧ
    OFTϑΝΠϧ෼ͷྖҬΛ
    NBMMPDͰ֬อ
    ʢFNTDSJQUFOΛ࢖༻ͨ͠৔߹
    .PEVMFʹੜ͑ͯΔʣ
    +4ଆ͔Β͸XBTNଆͷϝϞϦ͸"SSBZ#VGGFS
    ʹݟ͑ΔͷͰCZUF0GGTFUΛJ/&4σʔλͷઌ಄
    ʢ͢ͳΘͪϙΠϯλʣͱͯ͠αΠζͱҰॹʹڭ͑
    ͯ΍Δ

    View full-size slide

  31. #[no_mangle]
    pub fn run(len: usize, ptr: *mut u8) {
    let buf: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(ptr, len + 1) };
    let cassette = parse(buf);
    let prom = Rom::new(cassette.program_rom);
    let crom = Rom::new(cassette.character_rom);
    // ... লུ ….
    }
    pub fn parse(buf: &mut [u8]) -> Cassette {
    let program_rom_pages = buf[4] as usize;
    let character_rom_pages = buf[5] as usize;
    let character_rom_start = NES_HEADER_SIZE + program_rom_pages * PROGRAM_ROM_SIZE;
    let character_rom_end = character_rom_start + character_rom_pages * CHARACTER_ROM_SIZE;
    Cassette {
    program_rom: buf[NES_HEADER_SIZE..character_rom_start].to_vec(),
    character_ram: buf[character_rom_start..character_rom_end].to_vec(),
    }
    }
    3VTU XBTN
    ଆͷॳظԽॲཧ
    +4ଆ͔ΒJ/&4σʔλͷ
    αΠζͱϙΠϯλΛ΋Β͏
    QBSTF֤ͯ͠30.Λ෼཭
    ޙड़͢Δ$16͕ϓϩάϥϜ30.
    ͷ಺༰Λ࣮ߦ͢Ε͹ήʔϜ͕։࢝͢Δʣ

    View full-size slide

  32. #[no_mangle]
    pub fn run(len: usize, ptr: *mut u8) {
    let buf: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(ptr, len + 1) };
    let cassette = parse(buf);
    let prom = Rom::new(cassette.program_rom);
    let crom = Rom::new(cassette.character_rom);
    // ... লུ ….
    }
    pub fn parse(buf: &mut [u8]) -> Cassette {
    let program_rom_pages = buf[4] as usize;
    let character_rom_pages = buf[5] as usize;
    let character_rom_start = NES_HEADER_SIZE + program_rom_pages * PROGRAM_ROM_SIZE;
    let character_rom_end = character_rom_start + character_rom_pages * CHARACTER_ROM_SIZE;
    Cassette {
    program_rom: buf[NES_HEADER_SIZE..character_rom_start].to_vec(),
    character_ram: buf[character_rom_start..character_rom_end].to_vec(),
    }
    }
    3VTU XBTN
    ଆͷॳظԽॲཧ
    J/&4ϔομͷ৘ใ͔Β
    ֤30.Λ੾Γग़͢

    View full-size slide

  33. build:
    mkdir -p wasm
    rm -rf target/wasm32-unknown-emscripten/release/deps/*.wasm
    rm -rf target/wasm32-unknown-emscripten/release/rustynes.js
    cargo rustc --release \
    --target=wasm32-unknown-emscripten -- \
    -C opt-level=3 \
    -C link-args="-O3 -s -s EXPORTED_FUNCTIONS=['_run'] -s EXTRA_EXPORTED_RUNTIME_METHODS=['cwrap']" \
    --verbose
    cp target/wasm32-unknown-emscripten/release/rustynes.js wasm/rustynes.js
    cp target/wasm32-unknown-emscripten/release/deps/*.wasm wasm/rustynes.wasm
    wasm-gc wasm/rustynes.wasm wasm/rustynes.wasm
    ϏϧυίϚϯυ
    +4ଆʹFYQPSU͢Δؔ਺Λ
    ࢦఆͯ͠΍Δඞཁ͕͋Δ

    View full-size slide

  34. ϝϞϦʢ3".30.ʣ

    View full-size slide

  35. pub struct Ram {
    pub field: Vec,
    }
    impl Ram {
    pub fn new(buf: Vec) -> Ram {
    Ram { field: buf }
    }
    pub fn read(&self, addr: u16) -> u8 {
    self.field[addr as usize]
    }
    pub fn write(&mut self, addr: u16, data: u8) {
    self.field[addr as usize] = data;
    }
    }
    3".ͷ࣮૷

    View full-size slide

  36. $16͕ϝϞϦʹͲͷΑ͏ʹ
    ΞΫηε͢Δ͔஌ͬͯ·͔͢ʁ
    ׂ
    Ѫ

    View full-size slide

  37. ͲͷΑ͏ʹϝϞϦʹ
    ΞΫηε͢Δͷ͔ݟͯΈΔ
    ׂ
    Ѫ

    View full-size slide

  38. ΞυϨε
    νοϓηϨΫτ
    Ϧʔυ
    σʔλ
    Y%&"%
    Y#&
    43".ͷY%&"%൪஍ʹϦʔυΞΫηεΛߦ͍Y#&͕ಡΈग़͞ΕΔྫ
    43".ͷϦʔυλΠϛϯάྫ
    όεʹ͸ଞʹ΋༷ʑͳσόΠε͕઀ଓ͞ΕΔ
    Մೳੑ͕͋ΔͷͰͲͷσόΠε͕༗ޮ͔ࣔ͢৴߸
    νοϓηϨΫτɺΞυϨεɺϦʔυ৴߸ͳͲ
    Ϧʔυʹඞཁͳ৴߸͕ଗ͏ͱ3".͔Βσʔλ
    ׂ
    Ѫ

    View full-size slide

  39. ΞυϨε
    νοϓηϨΫτ
    Ϧʔυ
    σʔλ
    Y%&"%
    Y#&
    43".ͷY%&"%൪஍ʹϦʔυΞΫηεΛߦ͍Y#&͕ಡΈग़͞ΕΔྫ
    43".ͷϦʔυλΠϛϯάྫ
    ͜ͷλΠϛϯάͰY#&Λϥον͢Δ
    σʔλ͸Ϧʔυ৴߸ͷ্ཱ͕ͪΓ΍ͦͷޙͷ
    $16ΫϩοΫͷ্ཱ͕ͪΓͰऔΓࠐ·ΕΔ΋ͷ͕ଟ͍
    σόΠεʹϓϦϯτ͞Ε͍ͯΔ਺ࣈ͸͍͍ͩͨ͜͜ͷ਺ࣈ
    ʢDZDMF
    खݩͷ30.͸ͳͷͰ
    DZDMFOTҎ্ʹͯ͠Ͷͱ͍͏ҙຯ
    ׂ
    Ѫ

    View full-size slide

  40. ͢ͳΘͪɺ͜ΕΒͷ৴߸ΛλΠϛϯάΛकΓͭͭ
    ༩͑ͯ΍Ε͹Χηοτͷ30.͔Βσʔλ͕ಡΊΔ
    ׂ
    Ѫ

    View full-size slide

  41. w "QQMF**΍1$Τϯδϯʹ΋࠾༻͞Εͨϕʔε
    w ಈ࡞ΫϩοΫ͸.)[
    w .04͔ΒෆཁͳػೳΛ࡟ͬͯ"16ͱ%"$Λ࣮૷ͨ͠
    3JDPI੡ͷΧελϜ඼
    ϑΝϛίϯͷ$16

    View full-size slide

  42. $16ͷϨδελҰཡ
    ໊শ αΠζ ৄࡉ
    " CJU ΞΩϡϜϨʔλ
    9 CJU ΠϯσοΫεϨδελ
    : CJU ΠϯσοΫεϨδελ
    4 CJU ελοΫϙΠϯλ
    1 CJU εςʔλεϨδελ
    1$ CJU ϓϩάϥϜΧ΢ϯλ
    ελοΫϙΠϯλ͸ϏοτͷΞυϨεۭؒΛࢦ͢ඞཁ͕͋Δ͕
    ্ҐCJU͸Yʹݻఆ͞Ε͍ͯΔ
    ʢ83".ͷ͏ͪYʙY''ׂ͕Γ౰ͯΒΕΔʣ
    ͢ͳΘͪɺελοΫϙΠϯλϨδελ͕Y"ͷ৔߹ɺ
    ελοΫϙΠϯλ͸Y"ʹͳΔ
    ԋࢉ͸"ϨδελͰߦΘΕɺ9 :Ϩδελ͸ΠϯσοΫεʹ࢖༻͞ΕΔ


    View full-size slide

  43. εςʔλεϨδελ
    CJU ໊শ ৄࡉ ಺༰
    CJU / ωΨςΟϒ ԋࢉ݁ՌͷCJU͕ͷ࣌ʹηοτ
    CJU 7 Φʔόʔϑϩʔ 1ԋࢉ݁Ռ͕ΦʔόʔϑϩʔΛىͨ࣌͜͠ʹηο
    τ
    CJU 3 ༧໿ࡁΈ ৗʹηοτ͞Ε͍ͯΔ
    CJU # ϒϨʔΫϞʔυ #3,ൃੜ࣌ʹηοτɺ*32ൃੜ࣌ʹΫϦΞ
    CJU % σγϚϧϞʔυ σϑΥϧτɺ#$%Ϟʔυ ະ࣮૷

    CJU * *32ېࢭ *32ڐՄɺ*32ېࢭ
    CJU ; θϩ ԋࢉ݁Ռ͕ͷ࣌ʹηοτ
    CJU $ ΩϟϦʔ ΩϟϦʔൃੜ࣌ʹηοτ
    εςʔλεϨδελͷৄࡉ
    CJU͸ৗʹͰɺCJU͸/&4Ͱ͸ະ࣮૷

    *32͸ׂΓࠐΈɺ#3,͸ιϑτ΢ΤΞׂΓࠐΈ

    View full-size slide

  44. struct Status {
    negative: bool,
    overflow: bool,
    reserved: bool,
    break_mode: bool,
    decimal_mode: bool,
    interrupt: bool,
    zero: bool,
    carry: bool,
    }
    #[allow(non_snake_case)]
    pub struct Registers {
    A: u8,
    X: u8,
    Y: u8,
    SP: u8,
    PC: u16,
    P: Status,
    }
    $16ͷϨδελͷ࣮૷

    View full-size slide

  45. ΞυϨε αΠζ ༻్
    YʙY'' Y 83".
    YʙY''' 83".ͷϛϥʔ
    YʙY Y 116Ϩδελ
    YʙY''' 116Ϩδελͷϛϥʔ
    YʙY' Y "16*0ɺίϯτϩʔϥɺ%."
    YʙY''' Y'& ֦ு30.
    YʙY''' Y ֦ு3".
    YʙY#''' Y ϓϩάϥϜ30.
    Y$ʙY'''' Y ϓϩάϥϜ30.
    $16ͷϝϞϦϚοϓ
    Χηοτͷ
    ϓϩάϥϜ30.

    View full-size slide

  46. impl<'a> CpuBus for Bus<'a> {
    fn read_word(&mut self, addr: u16) -> u16 {
    // …লུ…
    }
    fn read(&mut self, addr: u16) -> u8 {
    match addr {
    0x0000...0x07FF => self.work_ram.read(addr),
    0x0800...0x1FFF => self.work_ram.read(addr - 0x0800),
    0x2000...0x3FFF => self.ppu.read(addr - 0x2000),
    0x4016 => self.keypad.read(),
    0x4017 => unimplemented!(), // 2player controller
    0x4000...0x401F => self.apu.read(addr - 0x4000),
    0x6000...0x7FFF => unimplemented!(), // battery back up ram
    0x8000...0xBFFF => self.program_rom.read(addr - 0x8000),
    0xC000...0xFFFF if self.program_rom.size() <= 0x4000 => self.program_rom.read(addr - 0xC000)
    0xC000...0xFFFF => self.program_rom.read(addr - 0x8000),
    _ => panic!("[READ] There is an illegal address. (0x{:x}) access detected.", addr),
    }
    }
    fn write(&mut self, addr: u16, data: u8) {
    // …লུ…
    }
    }
    $16͸$QV#VTϞδϡʔϧΛհ֤ͯ͠σόΠεʹΞΫηε͢ΔΑ͏ʹ
    $16όεͷ࣮૷
    ϝϞϦϚοϓΛ൓ө

    View full-size slide

  47. $16͸Ͳͷ൪஍͔Β
    ͲͷλΠϛϯάͰىಈ͢Δ͔

    View full-size slide

  48. ׂΓࠐΈ͕ൃੜ͢Δͱ$16͸ݱࡏͷ
    ίϯςΩετΛελοΫʹୀආ͠
    ࢦఆΞυϨεʢׂΓࠐΈϕΫλςʔϒϧʣ
    ʹ֨ೲ͞Εͨ൪஍ΑΓ࣮ߦ։࢝ʢ࠶։ʣ͢Δ
    ͷׂΓࠐΈ

    View full-size slide

  49. ͨͱ͑͹ɺϦηοτʢϑΝϛίϯͷ࢛֯ͷϘλϯͰ͢Ͷʣ΋ׂΓࠐΈͷҰछͰ
    Ϧηοτ͕ൃੜͨ͠৔߹Y'''$ɺY'''%͔ΒCJUͷΞυϨεΛϦʔυ͠
    1$ʢϓϩάϥϜΧ΢ϯλʣʹηοτ͠ɺηοτ͞ΕͨΞυϨε͔Β࣮ߦ͠·͢
    ׂΓࠐΈ ԼҐόΠτ ্ҐόΠτ ֓ཁ
    /.* Y'''" Y'''#
    ϊϯϚεΧϥϒϧׂΓࠐΈͱݴͬͯ$16͸ଆͰϚεΫͰ͖ͳ
    ׂ͍ΓࠐΈͰ͢ɻ116ͷׂΓࠐΈग़ྗ৴߸͕઀ଓ͞Ε͍ͯ·
    ͢
    3&4&5 Y'''$ Y'''% ϦηοτϘλϯԡԼ࣌΍ిݯ౤ೖ࣌ʹ͔͔ΔׂΓࠐΈͰ͢
    *32ɺ#3, Y'''& Y''''
    #3,͸ιϑτ΢ΣΞׂΓࠐΈͰ#3,໋ྩΛ࣮ߦͨ͠ͱ͖ʹൃ
    ੜ͠·͢ɻ*32͸"16΍Χηοτʹ઀ଓ͞Ε͍ͯ·͢
    ͷ৔߹ҎԼͷΑ͏ͳׂΓࠐΈཁҼ͕༻ҙ͞Ε͍ͯ·͢
    ͷׂΓࠐΈ

    View full-size slide

  50. ϦηοτׂΓࠐΈͷ৔߹

    View full-size slide

  51. pub fn reset(registers: &mut T,
    bus: &mut U) {
    let pc = bus.read_word(0xFFFC);
    registers.set_PC(pc);
    }
    جຊతʹ͸ϓϩάϥϜ30.͸Yʹ഑ஔ͞Ε͍ͯΔͷͰ
    Y'''$͔ΒYɺY'''%͔ΒY͕Ϧʔυ͞ΕΔέʔε͕ଟ͍
    ͦ͏͢Δͱ࣍αΠΫϧ͸ϓϩάϥϜ30.ͷઌ಄Ͱ͋ΔY͔Β࣮ߦ͞ΕΔ
    ϦηοτׂΓࠐΈͷ࣮૷
    Y'''$Λ্ҐόΠτ
    Y'''%ΛԼҐόΠτ
    ͱͨ͠CJUΛϦʔυ
    Ϧʔυ͞ΕͨCJUͷΞυϨεΛ
    1$ʢϓϩάϥϜΧ΢ϯλʣʹηοτ
    ࣍αΠΫϧ͸ηοτͨ͠ΞυϨε͔Β࣮ߦ͞ΕΔ

    View full-size slide

  52. pub fn process_nmi(registers: &mut T, bus: &mut U) {
    registers.set_break(false);
    push((registers.get_PC() >> 8) as u8, registers, bus);
    push(registers.get_PC() as u8, registers, bus);
    push_status(registers, bus);
    registers.set_interrupt(true);
    let next = bus.read_word(0xFFFA);
    registers.set_PC(next);
    }
    /.*ͷ࣮૷
    1$ͷ্ҐCJUɺ1$ͷԼҐCJU
    ͷॱʹελοΫʹ164)

    View full-size slide

  53. pub fn process_nmi(registers: &mut T, bus: &mut U) {
    registers.set_break(false);
    push((registers.get_PC() >> 8) as u8, registers, bus);
    push(registers.get_PC() as u8, registers, bus);
    push_status(registers, bus);
    registers.set_interrupt(true);
    let next = bus.read_word(0xFFFA);
    registers.set_PC(next);
    }
    /.*ͷ࣮૷
    εςʔλεϨδελΛ
    ελοΫʹ164)

    View full-size slide

  54. pub fn process_nmi(registers: &mut T, bus: &mut U) {
    registers.set_break(false);
    push((registers.get_PC() >> 8) as u8, registers, bus);
    push(registers.get_PC() as u8, registers, bus);
    push_status(registers, bus);
    registers.set_interrupt(true);
    let next = bus.read_word(0xFFFA);
    registers.set_PC(next);
    }
    /.*ͷ࣮૷
    Y'''" Y'''#͔ΒΞυϨεΛ
    Ϧʔυ͠1$ʹηοτ

    View full-size slide

  55. ྫ͑͹/.*લͷ1$͕YɺεςʔλεϨδελ͕Y""
    ελοΫϙΠϯλ͕Y''ͩͱ͢Δͱ/.*ޙͷελοΫ͸ҎԼͷΠϝʔδ
    Y''
    Y'&'
    Y'&&
    Y'&%
    Y'&
    ελοΫϙΠϯλ
    ʜ
    Y
    Y
    Y""
    1$ͷ্ҐΞυϨε
    1$ͷԼҐΞυϨε
    εςʔλεϨδελ
    ࣍ճͷ164)͸͜͜ʹੵ·ΕΔ
    /.*ͷ࣮ߦޙͷελοΫΠϝʔδ

    View full-size slide

  56. Ͱ͸"%$ Ճࢉ
    46# ݮࢉ
    ͳͲͷԋࢉͱ
    ԋࢉͷద༻ઌ΍ద༻ݩʢϨδελ΍ϝϞϦʣΛܾఆ͢Δ
    ΞυϨογϯάϞʔυ͕CJUͰදݱ͞Ε͍ͯΔ
    ͷ໋ྩ

    View full-size slide

  57. Y"͸-%"ͱ͍͏Ϩδελ"ʹ஋Λϩʔυ͢Δϩʔυ໋ྩͱ
    *NNFEJBUFͱ͍͏ଈ஋ΛऔΓѻ͏ΞυϨογϯάϞʔυ
    Y"͸-%"ͱ͍͏Ϩδελ"ʹ஋Λϩʔυ͢Δϩʔυ໋ྩͱ
    [FSPQBHFͱ͍͏্ҐCJU͕YͰ͋Δ൪஍Λૢ࡞͢ΔΞυϨογϯάϞʔυ
    ಉ͡-%"໋ྩͰ΋ΦϖϥϯυΛଈ஋ͱͯ͠ѻͬͨΓ্ҐYͷΞυϨεΛѻͬͨΓ
    ΞυϨγϯάϞʔυຖͷόϦΤʔγϣϯ͕͋Δ
    ԋࢉͷछྨºΞυϨογϯάϞʔυͰ໋ྩ͸໢ཏͰ͖ͦ͏
    -%"໋ྩ

    View full-size slide

  58. ུশ ໊લ ֓ཁ
    JNQM *NQMJFE ϨδελΛૢ࡞͢Δ
    " "DDVNVMBUPS "ϨδελΛૢ࡞͢Δ
    *NNFEJBUF Φϖίʔυ͕֨ೲ͞Ε͍ͯͨ࣍ͷ൪஍ʹ֨ೲ͞Ε͍ͯΔ஋Λσʔλͱͯ͠ѻ͏
    [QH ;FSPQBHF
    YΛ্ҐΞυϨεɺ1$ʢΦϖίʔυͷ࣍ͷ൪஍ʣʹ֨ೲ͞Εͨ஋ΛԼҐΞυϨεͱͨ͠൪஍Λԋ
    ࢉର৅ͱ͢Δ
    [QH 9
    [QH :
    ;FSPQBHF
    JOEFYFE
    YΛ্ҐΞυϨεɺ1$ʢΦϖίʔυͷ࣍ͷ൪஍ʣʹ֨ೲ͞Εͨ஋ʹ9Ϩδελ·ͨ͸:Ϩδελ
    ΛՃࢉͨ͠஋ΛԼҐΞυϨεͱͨ͠൪஍Λԋࢉର৅ͱ͢Δ
    BCT "CTPMVUF
    1$ʢΦϖίʔυͷ࣍ͷ൪஍ʣʹ֨ೲ͞Εͨ஋ΛԼҐΞυϨεɺ1$ʢΦϖίʔυͷ࣍ͷ࣍ͷ൪஍ʣʹ
    ֨ೲ͞Εͨ஋Λ্ҐΞυϨεͱͨ͠൪஍Λԋࢉର৅ͱ͢Δ
    BCT 9
    BCT :
    "CTPMVUF
    JOEFYFE
    "CTPMVUF"EESFTTJOHͰಘΒΕΔ஋ʹ9Ϩδελ·ͨ͸:ϨδελΛՃࢉͨ͠൪஍Λԋࢉର৅ͱ͢Δ
    SFM 3FMBUJWF 1$ʢΦϖίʔυͷ࣍ͷ൪஍ʣʹ֨ೲ͞Εͨ஋ͱͦͷ࣍ͷ൪஍ΛՃࢉͨ͠൪஍Λԋࢉର৅ͱ͢Δ
    9 *OE
    *OEFYFE
    *OEJSFDU
    YΛ্ҐΞυϨεɺ1$ʢΦϖίʔυͷ࣍ͷ൪஍ʣʹ֨ೲ͞Εͨ஋ΛԼҐΞυϨεͱͨ͠൪஍ʹϨ
    δελ9ͷ஋ΛՃࢉɺͦͷ൪஍ͷ஋ΛԼҐΞυϨεɺͦͷ࣍ͷ൪஍ͷ஋Λ্ҐΞυϨεͱͨ͠൪஍Λ
    ԋࢉର৅ͱ͢Δ
    *OE :
    *OEJSFDU
    JOEFYFE
    YΛ্ҐΞυϨεɺ1$ʢΦϖίʔυͷ࣍ͷ൪஍ʣʹ֨ೲ͞Εͨ஋ΛԼҐΞυϨεͱͨ͠൪஍ͷ஋
    ΛԼҐΞυϨεɺͦͷ࣍ͷ൪஍ͷ஋Λ্ҐΞυϨεͱͨ͠൪஍ʹϨδελ:ΛՃࢉͨ͠൪஍Λԋࢉର
    ৅ͱ͢Δ
    *OE
    "CTPMVUF
    JOEFYFE
    "CTPMVUF"EESFTTJOHͰಘΒΕΔ൪஍ʹ֨ೲ͞Ε͍ͯΔ஋ΛԼҐΞυϨεɺͦͷ࣍ͷ൪஍ʹ֨ೲ͞
    Ε͍ͯΔ஋Λ্ҐΞυϨεͱͨ͠൪஍Λԋࢉର৅ͱ͢Δ
    ΞυϨογϯάϞʔυ

    View full-size slide

  59. ໋͍͔ͭ͘ྩΛϐοΫΞοϓ
    ͯ͠આ໌͠·͢

    View full-size slide

  60. -%"JNN
    ଈ஋Λ"Ϩδελʹϩʔυ͢Δ

    View full-size slide

  61. Yʹͱ͍͏໋ྩ͕֨ೲ͞Ε͍ͯΔ৔߹
    ϝϞϦͱ࣮ߦखॱҎԼͷΑ͏ʹͳΔʢ1$΋Yͱ͢Δʣ
    -%"
    ʢY"ʣ
    Y
    Y"
    Y
    ʜ
    Y
    -%""
    $16͸1$ ͢ͳΘͪY
    ͔Β໋ྩΛϑΣον͠1$Λ
    ϑΣον݁ՌY"͔Β-%"JNNͰ͋Δͱ൑ผ͞ΕΔ
    $16͸Y͔ΒΦϖϥϯυY"ΛϑΣον͠1$Λ
    Ϩδελ"ʹY"Λ֨ೲ͠ɺ࣍ͷ໋ྩ΁
    -%"JNN
    ࣍ͷ໋ྩ
    ͜ͷ஋Λ"Ϩδελ
    ʹϩʔυ͢Δ
    1$

    View full-size slide

  62. pub fn lda_imm(operand: Word, registers: &mut T) {
    registers
    .set_A(operand as Data)
    .update_negative_by(operand as Data)
    .update_zero_by(operand as Data);
    }
    #[test]
    fn test_lda_immediate() {
    let mut reg = Registers::new();
    lda_imm(0xA5, &mut reg);
    assert_eq!(reg.get_A(), 0xA5);
    }
    ଈ஋Λ"Ϩδελʹϩʔυ͢Δ
    -%"JNN
    "ϨδελʹΦϖϥϯυ
    ʹηοτ
    ηοτ͞Εͨ஋ʹରԠ͢Δ
    εςʔλεϑϥάΛηοτ

    View full-size slide

  63. -%"[QH
    ্ҐΛYԼҐΛΦϖϥϯυͱͨ͠ΞυϨεʹ
    ֨ೲ͞Ε͍ͯΔ஋Λ"Ϩδελʹϩʔυ͢Δ

    View full-size slide

  64. Yʹͱ͍͏໋ྩ͕֨ೲɺYʹ
    Y"͕֨ೲ͞Ε͍ͯΔ৔߹ϝϞϦͱ࣮ߦखॱҎԼͷΑ͏ʹͳΔ
    ʢ1$΋Yͱ͢Δʣ
    -%"
    ʢY"ʣ
    Y
    Y
    Y
    ʜ
    Y
    -%"
    $16͸1$ ͢ͳΘͪY
    ͔Β໋ྩΛϑΣον͠1$Λ
    ϑΣον݁ՌY"͔Β-%"[QHͰ͋Δͱ൑ผ͞ΕΔ
    $16͸Y͔ΒΦϖϥϯυYΛϑΣον͠1$Λ
    $16͸Y͔ΒY"ΛϦʔυ
    Ϩδελ"ʹY"Λ֨ೲ͠ɺ࣍ͷ໋ྩ΁
    Y"
    Y
    ʜ
    Y
    ʜ
    Y
    ᶃY൪஍ͷ಺༰ΛϦʔυ
    ᶄY"Λ"Ϩδελʹηοτ
    -%"[QH
    ࣍ͷ໋ྩ
    1$

    View full-size slide

  65. pub fn lda(operand: Word, registers: &mut T, bus: &mut U) {
    let computed = bus.read(operand);
    registers
    .set_A(computed)
    .update_negative_by(computed)
    .update_zero_by(computed);
    }
    #[test]
    fn test_lda() {
    let mut reg = Registers::new();
    let mut bus = MockBus::new();
    bus.mem[0xAA] = 0xA5;
    lda(0xAA, &mut reg, &mut bus);
    assert_eq!(reg.get_A(), 0xA5);
    }
    -%"[QH
    ্ҐΛYԼҐΛΦϖϥϯυͱͨ͠ΞυϨεʹ
    ֨ೲ͞Ε͍ͯΔ஋Λ"Ϩδελʹϩʔυ͢Δϩʔυ͢Δ
    Φϖϥϯυͷ஋ΞυϨεͱͯ͠Ϧʔυ
    Ϧʔυ͞Εͨ஋Λ"Ϩδελʹηοτ

    View full-size slide

  66. ͜͜·Ͱͷ$16ͷಈ࡞Λ·ͱΊΔͱ

    View full-size slide

  67. Ϧηοτ
    ແ͠
    ແ͠
    ༗Γ
    ༗Γ
    ׂΓࠐΈ
    ༗ແ
    Φϖϥϯυ
    ༗ແ
    Ϩδελͷ
    ঢ়ଶΛୀආ
    1$͔Β໋ྩ
    ΛϑΣον 1$

    1$͔ΒΦϖϥϯυΛ
    ϑΣον 1$

    ໋ྩΛ࣮ߦ
    ׂΓࠐΈϕΫλ
    ͷ஋Λ1$
    ʹηοτ
    $16ͷಈ࡞Πϝʔδ
    Y'''$'''%ʹ
    ֨ೲ͞Εͨ൪஍͔Β։࢝

    View full-size slide

  68. pub fn run(
    registers: &mut T,
    bus: &mut U,
    nmi: &mut bool,
    ) -> Data {
    if *nmi {
    process_nmi(registers, bus);
    *nmi = false;
    }
    let code = fetch(registers, bus);
    let ref map = opecode::MAP;
    let code = &*map.get(&code).unwrap();
    let operand = fetch_operand(&code, registers, bus);
    match code.name {
    Instruction::LDA if code.mode == Addressing::Immediate => lda_imm(operand, registers),
    Instruction::LDA => lda(operand, registers, bus),
    // …লུ…
    }
    code.cycle
    }
    $16ͷ࣮૷
    ׂΓࠐΈͷνΣοΫ

    View full-size slide

  69. pub fn run(
    registers: &mut T,
    bus: &mut U,
    nmi: &mut bool,
    ) -> Data {
    if *nmi {
    process_nmi(registers, bus);
    *nmi = false;
    }
    let code = fetch(registers, bus);
    let ref map = opecode::MAP;
    let code = &*map.get(&code).unwrap();
    let operand = fetch_operand(&code, registers, bus);
    match code.name {
    Instruction::LDA if code.mode == Addressing::Immediate => lda_imm(operand, registers),
    Instruction::LDA => lda(operand, registers, bus),
    // …লུ…
    }
    code.cycle
    }
    $16ͷ࣮૷
    1$͔Β໋ྩΛϑΣον
    σίʔυ
    ࣙॻ͔Β໋ྩͷछผɾΞυϨογϯά
    ϞʔυɺαΠΫϧ਺ͳͲΛҾ͍ͯ͘Δ

    View full-size slide

  70. $16ͷ࣮૷
    let mut m = HashMap::new();
    m.insert(0xA9, Opecode { name: Instruction::LDA, mode: Addressing::Immediate, cycle: cycles[0xA9] });
    m.insert(0xA5, Opecode { name: Instruction::LDA, mode: Addressing::ZeroPage, cycle: cycles[0xA5] });
    m.insert(0xB5, Opecode { name: Instruction::LDA, mode: Addressing::ZeroPageX, cycle: cycles[0xB5] });
    m.insert(0xAD, Opecode { name: Instruction::LDA, mode: Addressing::Absolute, cycle: cycles[0xAD] });
    m.insert(0xBD, Opecode { name: Instruction::LDA, mode: Addressing::AbsoluteX, cycle: cycles[0xBD] });
    m.insert(0xB9, Opecode { name: Instruction::LDA, mode: Addressing::AbsoluteY, cycle: cycles[0xB9] });
    m.insert(0xA2, Opecode { name: Instruction::LDX, mode: Addressing::Immediate, cycle: cycles[0xA2] });
    m.insert(0xA6, Opecode { name: Instruction::LDX, mode: Addressing::ZeroPage, cycle: cycles[0xA6] });
    // …লུ…
    ΞυϨογϯάϞʔυ΍αΠΫϧ਺
    Λ൑ผ

    View full-size slide

  71. pub fn run(
    registers: &mut T,
    bus: &mut U,
    nmi: &mut bool,
    ) -> Data {
    if *nmi {
    process_nmi(registers, bus);
    *nmi = false;
    }
    let code = fetch(registers, bus);
    let ref map = opecode::MAP;
    let code = &*map.get(&code).unwrap();
    let operand = fetch_operand(&code, registers, bus);
    match code.name {
    Instruction::LDA if code.mode == Addressing::Immediate => lda_imm(operand, registers),
    Instruction::LDA => lda(operand, registers, bus),
    // …লུ…
    }
    code.cycle
    }
    $16ͷ࣮૷
    1$͔ΒΦϖϥϯυΛϑΣον
    αΠΫϧ਺Λฦ͢
    -%"JNNҎ֎ͷ-%"໋ྩ
    -%"JNN໋ྩ

    View full-size slide

  72. ͋ͱ͸໋֤ͭͭ͜͜ྩΛ࣮૷$

    View full-size slide

  73. ͪͳΈʹޮ཰ͷ͍͍ςετํ๏͸

    View full-size slide

  74. ςετ30.Λ࢖༻͢Δ

    View full-size slide

  75. w ϐΫνϟʔϓϩηογϯάϢχοτͷུ
    w 73".ͳͲͷ಺༰Λ΋ͱʹεϓϥΠτͱόοΫάϥ΢ϯυ
    ͷϨΠϠʔΛ߹੒ͯ͠ग़ྗ͢Δ
    w $16ͷഒͷΫϩοΫͰಈ࡞
    w ͍Θ͹ݪ࢝తͳ(16ͱ͍ͬͯ΋͍͍͔΋
    116ͱ͸

    View full-size slide

  76. 116ͷϝϞϦϚοϓ

    View full-size slide

  77. ΞυϨε αΠζ ֓ཁ
    YʙY''' Y ύλʔϯςʔϒϧ
    YʙY''' Y ύλʔϯςʔϒϧ
    YʙY#' Y$ ωʔϜςʔϒϧ
    Y$ʙY'' Y ଐੑςʔϒϧ
    YʙY#' Y$ ωʔϜςʔϒϧ
    Y$ʙY'' Y ଐੑςʔϒϧ
    YʙY##' Y$ ωʔϜςʔϒϧ
    Y#$ʙY#'' Y ଐੑςʔϒϧ
    Y$ʙY'#' Y$ ωʔϜςʔϒϧ
    Y'$ʙY''' Y ଐੑςʔϒϧ
    YʙY&'' YY&''ͷϛϥʔ
    Y'ʙY'' Y όοΫάϥ΢ϯυύϨοτςʔϒϧ
    Y'ʙY'' Y εϓϥΠτύϨοτςʔϒϧ
    Y'ʙY''' Y'Y''ͷϛϥʔ
    116ͷϝϞϦϚοϓ
    Χηοτͷ
    ΩϟϥΫλʔ30.

    View full-size slide

  78. Α͘Θ͔Βͳ͍ςʔϒϧ
    ͕͍ͬͺ͍

    View full-size slide

  79. ϝϞϦϚοϓͷ֤߲໨ʹ͍ͭͯ
    આ໌͍ͯ͘͠

    View full-size slide

  80. ωʔϜςʔϒϧ

    View full-size slide

  81. 73".ྖҬ಺഑ஔ͞ΕΔɺը໘ʹରͯ͠ͲͷΑ͏ʹ
    എܠλΠϧΛෑ͖٧ΊΔ͔ΛܾΊΔςʔϒϧ
    ը໘ղ૾౓͸YϐΫηϧͳͷͰYϐΫηϧͷλΠϧ͕
    Yʢ͢ͳΘͪຕʣͰෑ͖٧ΊΒΕΔ͜ͱʹͳΔ
    ͳͷͰ
    ֤ωʔϜςʔϒϧͷαΠζ͸
    Y$#ZUF
    ωʔϜςʔϒϧͱ͸

    View full-size slide

  82. ͨͱ͑͹ҎԼͷը໘ͷ৔߹Y$ͷՕॴʹ)͕දࣔ͞͞ΕͯΔ
    ͢ͳΘͪɺɹɹʹ)Λද͢εϓϥΠτ൪߸Λॻ͖ࠐΊ͹͜ͷҐஔʹɹ͕දࣔ͞ΕΔ
    ωʔϜςʔϒϧ
    ͷઌ಄
    λΠϧ
    λΠϧ
    ωʔϜςʔϒϧ
    ͷ$൪஍ʹ૬౰
    Y$൪஍ )
    ωʔϜςʔϒϧ
    ͷऴ୺
    ωʔϜςʔϒϧͱ͸

    View full-size slide

  83. )FMMP 8PSMEͷαϯϓϧ30.ͷΩϟϥΫλʔ30.ͷ಺༰͸ҎԼͷΑ͏ʹͳ͍ͬͯΔ
    )ͷΠϯσοΫε͸ͳͷͰ
    ɺɹɹʹ)Λද͢ΛϥΠτ͢Ε͹Α͍
    Y$൪஍
    ωʔϜςʔϒϧͱ͸

    View full-size slide

  84. ଐੑςʔϒϧ

    View full-size slide

  85. എܠʹͲͷύϨοτΛద༻͢Δ͔Λܾఆ͢Δςʔϒϧ
    ஫ҙ఺ͱͯ͠͸ύϨοτ͸YϐΫηϧͷϒϩοΫ୯Ґ
    ͢ͳΘͪʢYλΠϧʣʹύϨοτʢ̐৭ʣద༻͞ΕΔ
    ϒϩοΫʹ͖ͭCJUͷ৘ใΛ͓࣋ͬͯΓɺը໘YͳͷͰ
    YϒϩοΫϒϩοΫɺϒϩοΫʹ͖ͭCJU
    ͳͷͰόΠτͷྖҬΛ࢖༻͢Δ
    ଐੑςʔϒϧͱ͸

    View full-size slide

  86. ྫ͑͹ଐੑςʔϒϧͷઌ಄൪஍Ͱ͋ΔY$൪஍͕Y&Ͱ͋Ε͹
    @@@CͳͷͰҎԼͷΑ͏ʹϒϩοΫʹద༻͞ΕΔύϨοτ͕ܾఆ͢Δ
    ԾʹҎԼͷύϨοτ͕ઃఆ͞Ε͍ͯͨͱ͢Δͱ
    λΠϧ ϒϩοΫ

    λΠϧ ϒϩοΫ



    ͜ͷϒϩοΫ Y
    ͸
    ͳͷͰ͕
    ࢖༻Ͱ͖Δ
    ύϨοτ

    ͜ͷϒϩοΫ͸
    ͜ͷϒϩοΫ͸
    ͜ͷϒϩοΫ͸
    ଐੑςʔϒϧͱ͸

    View full-size slide

  87. ύϨοτςʔϒϧ

    View full-size slide

  88. എܠ༻ʹ৭ͷύϨοτ͕ͭʢY'ʙY''ʣ
    εϓϥΠτ༻ʹ̐৭ͷύϨοτ͕ͭʢY'ʙY''ʣ
    ༻ҙ͞Ε͍ͯΔ
    ͨͩ͠ɺ֤എܠ༻ύϨοτͷઌ಄ͷ৭͸എܠ৭
    ֤εϓϥΠτ༻ύϨοτͷઌ಄ͷ৭͸ಁ໌ͱͯ͠ѻΘΕΔ
    ಉ࣌ʹ࢖༻Ͱ͖Δ৭͸എܠ༻͸࠷େ৭
    εϓϥΠτ༻͸࠷େ৭ಉ࣌ʹ࢖༻Ͱ͖Δ
    ύϨοτςʔϒϧͱ͸

    View full-size slide

  89. ͨͱ͑͹εύʔϚϦΦϒϥβʔεͷΦʔϓχϯάը໘͸ҎԼͷΑ͏ͳ
    ύϨοτ͕ઃఆ͞Ε͍ͯΔ
    ύϨοτY' ύϨοτY' ύϨοτY' ύϨοτY'$
    ύϨοτY' ύϨοτY' ύϨοτY' ύϨοτY'$
    എܠ༻ύϨοτʢഎܠ৭৭৭YύϨοτͰ৭ʣ
    εϓϥΠτ༻ύϨοτʢ৭͸ಁ໌৭ͳͷͰ৭YύϨοτͰ৭ʣ
    ֤ςʔϒϧͷઌ಄
    ͸ಁ໌৭ͱͯ͠
    ѻΘΕΔ
    ಁ໌৭ ಁ໌৭ ಁ໌৭
    ֤ςʔϒϧͷઌ಄
    ͸എܠ৭
    എܠ৭ എܠ৭ എܠ৭
    ϚϦΦ͸ӈଆͷ৭Ͱදݱ͞Ε͍ͯΔ
    ύϨοτςʔϒϧͱ͸

    View full-size slide

  90. ஋ͱ৭ͱͷରԠ͸ʁ

    View full-size slide

  91. IUUQTXJLJOFTEFWDPNXJOEFYQIQ116@QBMFUUFTΑΓ
    ϑΝϛίϯͷ৭͸116͕/54$৴߸Λ௚઀ੜ੒͢Δؔ܎্3(#Ͱ͸ͳ͘
    ً౓ʢϧϛφϯεʣͱ৭౓ʢΫϩϚʣͰදݱ͞ΕΔ
    ͨͱ͑͹εʔύʔϚϦΦϒϥβʔεͷۭͷ৭͸Y͸ҎԼͷΑ͏ͳҙຯΛ΋ͭ
    Y
    @C
    ৗʹ ً౓ ৭౓
    ύϨοτͷ৭
    ً౓
    ৭౓

    View full-size slide

  92. 116ͷϨδελΛோΊΔ

    View full-size slide

  93. ΞυϨε ֓ཁ
    Y
    Y
    CJU આ໌
    7#MBOL࣌ʹׂΓࠐΈΛग़ྗ
    ৗʹ̍
    εϓϥΠταΠζYY
    എܠ༻ύλʔϯςʔϒϧΞυϨεYY
    εϓϥΠτύλʔϯςʔϒϧΞυϨεYY
    116ΞυϨεΠϯΫϦϝϯτ
    ωʔϜςʔϒϧࢦఆ
    CJU આ໌
    എܠ৭CࠇC྘C੨C੺

    εϓϥΠτΠωʔϒϧσΟηʔϒϧΠωʔϒϧ
    എܠΠωʔϒϧσΟηʔϒϧΠωʔϒϧ
    εϓϥΠτͷը໘ࠨϐΫηϧඳըඳը͠ͳ͍ඳը͢Δ
    എܠͷը໘ࠨϐΫηϧඳըඳը͠ͳ͍ඳը͢Δ
    σΟεϓϨΠλΠϓΧϥʔϞϊΫϩ
    116ͷϨδελ 8SJUF

    View full-size slide

  94. ΞυϨε ֓ཁ
    Y
    εϓϥΠτϝϞϦΞυϨε
    YΛܦ༝ͯ͠εϓϥΠτϝϞϦ΁ॻ͖ࠐΉϏοτΞυϨεΛࢦఆ
    Y
    εϓϥΠτϝϞϦσʔλ
    YʹΑͬͯࢦఆ͞ΕͨεϓϥΠτϝϞϦΞυϨε΁σʔλΛॻ͖ࠐΉɻ
    ॻ͖ࠐΉ౓ʹεϓϥΠτϝϞϦΞυϨε͸ΠϯΫϦϝϯτ
    ͞ΕΔɻ
    Y
    എܠεΫϩʔϧΦϑηοτ
    ճϥΠτΛߦ͏͜ͱͰ9ɺ:ͷॱʹεΫϩʔϧ஋͕ઃఆ͞ΕΔ
    Y
    116"%%3 116ϝϞϦΞυϨε

    YΛܦ༝ͯ͠116ϝϞϦ΁ॻ͖ࠐΉϏοτΞυϨεΛࢦఆ͢Δɻ্ҐϏοτɺԼҐϏοτͷॱ
    ʹॻ͖ࠐΉɻ
    Y
    116%"5" 116ϝϞϦσʔλ

    YʹΑͬͯࢦఆ͞Εͨ116ϝϞϦΞυϨε΁σʔλΛॻ͖ࠐΉɻॻ͖ࠐΉ౓ʹϝϞϦΞυϨε͸Π
    ϯΫϦϝϯτ YͷϏοτʹΑͬͯɺ
    ͢Δɻ
    116ͷϨδελ 8SJUF

    View full-size slide

  95. ΞυϨε ֓ཁ
    Y
    Y
    εϓϥΠτϝϞϦσʔλ
    YʹΑͬͯࢦఆ͞ΕͨεϓϥΠτϝϞϦΞυϨε΁σʔλΛϦʔυ͢Δ
    Ϧʔυ͢Δ౓ʹεϓϥΠτϝϞϦΞυϨε͸ΠϯΫϦϝϯτ
    ͞ΕΔɻ
    Y
    116ϝϞϦσʔλ
    YʹΑͬͯࢦఆ͞Εͨ116ϝϞϦΞυϨεͷσʔλΛϦʔυ͢Δ
    Ϧʔυ͢Δ౓ʹϝϞϦΞυϨε͸ΠϯΫϦϝϯτ YͷϏοτʹΑͬͯɺ
    ͢Δɻ
    CJU આ໌
    7CMBOL࣌ʹ
    εϓϥΠτώοτ࣌ʹ
    εΩϟϯϥΠϯεϓϥΠτ਺ɹݸҎԼݸҎ্
    3FTFSWFE
    116ͷϨδελ 3FBE

    View full-size slide

  96. ͔͜͜Βॏཁͳ΋ͷΛൈ͖ग़ͯ͠
    ౎౓આ໌͍͖ͯ͠·͢

    View full-size slide

  97. தͰ΋ॏཁͳͷ͸

    View full-size slide

  98. 116"%%3116%"5"Ϩδελ

    View full-size slide

  99. 116ͷϝϞϦۭؒʢ73".ͳͲʣʹ$16͔ΒಡΈॻ͖͢ΔͨΊͷϨδελ
    $16
    116
    116"%%3
    116%"5"
    73".
    ΩϟϥΫλʔ30.
    73".΍ΩϟϥΫλʔ30.͸116όεʹ઀ଓ͞Ε͓ͯΓ
    $16͔Β͸௚઀ΞΫηεͰ͖ͳ͍
    ͦͷͨΊ116"%%3116%"5"Λհͯ͠ಡΈॻ͖͢Δ
    $16όε 116όε
    116"%%3116%"5"Ϩδελ

    View full-size slide

  100. Ͳ͏΍ͬͯ࢖͏͔

    View full-size slide

  101. 116ͷϝϞϦۭؒʢ73".ͳͲʣʹ$16͔ΒಡΈॻ͖͢ΔͨΊͷϨδελ
    116"%%3 Y
    ʹ̎ճॻ͖ࠐΈ͜ͱͰ116ϝϞϦۭؒΛࢦఆ
    ྫ͑͹Y' YΛ116"%%3ʹॻ͖ࠐΉ͜ͱͰ
    116ΞυϨε͕Y'ʹηοτ͞ΕΔ
    116%"5" Y
    ʹϦʔυϥΠτ͢Δ͜ͱͰ116"%%3
    Ͱࢦఆͨ͠116ϝϞϦۭؒΛಡΈॻ͖͢Δ͜ͱ͕Ͱ͖Δ
    ʢಡΈॻ͖Λ͢Δͱ116"%%3͸ࣗಈతʹ ·ͨ͸
    ΠϯΫϦϝϯτ͞ΕΔʣ
    116"%%3116%"5"Ϩδελ

    View full-size slide

  102. ͜͜·Ͱͷ࿩͔͠Β͢Δͱ
    73".ͷ಺༰Λى఺ʹ
    Ճ޻͍͚ͯ͠͹
    ϐΫηϧσʔλΛੜ੒Ͱ͖ͦ͏

    View full-size slide

  103. ωʔϜςʔϒϧ͔ΒͲͷഎܠεϓϥΠτ͕഑ஔ͞Ε͍ͯΔ͔Ϧʔυ͢Δ
    Ϧʔυ͞ΕͨεϓϥΠτ൪߸ΛݩʹΧηοτ͔Βը૾σʔλΛಡΜͰ͘Δ
    ଐੑςʔϒϧ͔ΒഎܠεϓϥΠτʹద༻͞ΕΔύϨοτ൪߸ΛಡΜͰ͘Δ
    ύϨοτςʔϒϧ͔ΒύϨοτͷ৭ΛಡΜͰ͘Δ
    എܠεϓϥΠτͷCJU৘ใΛݩʹύϨοτ͔Βண৭͢Δ
    ͜ͷखॱͰωʔϜςʔϒϧ͔Β
    YQYͷϐΫηϧσʔλ͕ͭ͘ΕΔ͸ͣ
    116ඳըखॱΠϝʔδ

    View full-size slide

  104. ΋͏ͪΐͬͱ۩ମతͳྫ

    View full-size slide

  105. )FMMP 8PSMEͷ)ΛωʔϜςʔϒϧ͔ΒϐΫηϧσʔλʹͯ͠ΈΔྫ
    ωʔϜςʔϒϧͷΛϦʔυ͠εϓϥΠτ൪߸ΛಘΔ
    εϓϥΠτ͸ΩϟϥΫλʔ30.಺ʹ#ZUFͣͭฒΜͰ͍ΔͷͰ
    YYY͔Β#ZUFϦʔυ͠εϓϥΠτΛ૊ΈཱͯΔ
    Y$൪஍








    Y
    ֘౰ͷ࠲ඪ͸ଐੑςʔϒϧͷΞυϨεY%"ʹ֘౰͢ΔͨΊ
    73".ͷ͔ΒΞτϦϏϡʔτ͕Ϧʔυ͞ΕΔ
    Y%"൪஍ Y
    116ඳըखॱΠϝʔδ
    ͜ΜͳεϓϥΠτ
    σʔλ͕ಘΒΕΔ

    View full-size slide

  106. Ϧʔυ͞ΕͨΞτϦϏϡʔτ͔Β֘౰ϙδγϣϯͷύϨοτ൪߸Λ
    औΓग़͢ͱʹͳΔͷͰύϨοτ͕ద༻͞ΕΔ͜ͱ͕Θ͔Δ
    ύϨοτ͢ͳΘͪ73".ͷ#ZUFಡΉͱ
    ͕ϦʔυͰ͖Δɻ͜ΕΛΧϥʔίʔυදʹద༻͢Δͱ࣍ͷ৭Ͱ͋Δ͜ͱ͕Θ͔Δ
    ͨΊ3(#ʹม׵֤͠ϐΫηϧʹύϨοτΛద༻ͯ͠΍Δͱ׬੒







    ύϨοτ̌
    ׬੒✨
    C
    Y'd Y' Y Y Y
    116ඳըखॱΠϝʔδ
    )FMMP 8PSMEͷ)ΛωʔϜςʔϒϧ͔ΒϐΫηϧσʔλʹͯ͠ΈΔྫ

    View full-size slide

  107. impl Tile {
    pub fn new(
    vram: &Ram,
    cram: &Ram,
    palette: &P,
    position: &SpritePosition,
    config: &SpriteConfig,
    ) -> Self {
    let block_id = get_block_id(position);
    let sprite_id = get_sprite_id(&vram, position, config);
    let attr = get_attribute(&vram, position, config);
    let palette_id = (attr >> (block_id * 2)) & 0x03;
    let sprite = build(&cram, sprite_id, config.offset_addr_by_background_table);
    Tile { sprite, palette: palette.get(palette_id, PaletteType::Background) }
    }
    }
    pub fn build(cram: &Ram, sprite_id: u8, offset: u16) -> Sprite {
    let mut sprite: Sprite = (0..8).into_iter().map(|_| vec![0; 8]).collect();
    for i in 0..16 {
    for j in 0..8 {
    let addr = (sprite_id as u16) * 16 + i + offset;
    let ram = cram.read(addr);
    if ram & (0x80 >> j) as u8 != 0 {
    sprite[(i % 8) as usize][j] += (0x01 << (i / 8)) as u8;
    }
    }
    }
    sprite
    }
    116ඳըखॱΠϝʔδ
    ࠲ඪ͔ΒϒϩοΫ൪߸
    Λࢉग़
    ࠲ඪͱωʔϜςʔϒϧ͔Β
    εϓϥΠτ൪߸Λࢉग़

    View full-size slide

  108. impl Tile {
    pub fn new(
    vram: &Ram,
    cram: &Ram,
    palette: &P,
    position: &SpritePosition,
    config: &SpriteConfig,
    ) -> Self {
    let block_id = get_block_id(position);
    let sprite_id = get_sprite_id(&vram, position, config);
    let attr = get_attribute(&vram, position, config);
    let palette_id = (attr >> (block_id * 2)) & 0x03;
    let sprite = build(&cram, sprite_id, config.offset_addr_by_background_table);
    Tile { sprite, palette: palette.get(palette_id, PaletteType::Background) }
    }
    }
    pub fn build(cram: &Ram, sprite_id: u8, offset: u16) -> Sprite {
    let mut sprite: Sprite = (0..8).into_iter().map(|_| vec![0; 8]).collect();
    for i in 0..16 {
    for j in 0..8 {
    let addr = (sprite_id as u16) * 16 + i + offset;
    let ram = cram.read(addr);
    if ram & (0x80 >> j) as u8 != 0 {
    sprite[(i % 8) as usize][j] += (0x01 << (i / 8)) as u8;
    }
    }
    }
    sprite
    }
    116ඳըखॱΠϝʔδ
    ࠲ඪͱଐੑςʔϒϧ͔Β
    ΞτϦϏϡʔτΛࢉग़
    ΞτϦϏϡʔτͱϒϩοΫ൪߸͔Β
    ύϨοτ൪߸Λࢉग़

    View full-size slide

  109. impl Tile {
    pub fn new(
    vram: &Ram,
    cram: &Ram,
    palette: &P,
    position: &SpritePosition,
    config: &SpriteConfig,
    ) -> Self {
    let block_id = get_block_id(position);
    let sprite_id = get_sprite_id(&vram, position, config);
    let attr = get_attribute(&vram, position, config);
    let palette_id = (attr >> (block_id * 2)) & 0x03;
    let sprite = build(&cram, sprite_id, config.offset_addr_by_background_table);
    Tile { sprite, palette: palette.get(palette_id, PaletteType::Background) }
    }
    }
    pub fn build(cram: &Ram, sprite_id: u8, offset: u16) -> Sprite {
    let mut sprite: Sprite = (0..8).into_iter().map(|_| vec![0; 8]).collect();
    for i in 0..16 {
    for j in 0..8 {
    let addr = (sprite_id as u16) * 16 + i + offset;
    let ram = cram.read(addr);
    if ram & (0x80 >> j) as u8 != 0 {
    sprite[(i % 8) as usize][j] += (0x01 << (i / 8)) as u8;
    }
    }
    }
    sprite
    }
    116ඳըखॱΠϝʔδ
    εϓϥΠτ൪߸͔Β
    YͷϐΫηϧσʔλΛ
    ࡞੒

    View full-size slide

  110. fn render_tile(&mut self, bg: &BackgroundCtx, x: usize, y: usize) {
    let offset_x = (bg.scroll_x % 8) as i32;
    let offset_y = (bg.scroll_y % 8) as i32;
    for i in 0..8 {
    for j in 0..8 {
    let x = (x + j) as i32 - offset_x;
    let y = (y + i) as i32 - offset_y;
    if x >= 0 as i32 && 0xFF >= x && y >= 0 as i32 && y < 224 {
    let color_id = bg.tile.palette[bg.tile.sprite[i][j] as usize];
    let color = COLORS[color_id as usize];
    let index = ((x + (y * 0x100)) * 4) as usize;
    self.buf[index] = color.0;
    self.buf[index + 1] = color.1;
    self.buf[index + 2] = color.2;
    if x < 8 {
    self.buf[index + 3] = 0;
    }
    }
    }
    }
    }
    pub static COLORS: &'static [(u8, u8, u8)] = &[
    (0x80, 0x80, 0x80), (0x00, 0x3D, 0xA6), (0x00, 0x12, 0xB0), (0x44, 0x00, 0x96), …লུ…
    ];
    116ඳըखॱΠϝʔδ
    ً౓ɺ৭౓ͷσʔλΛ
    3(#ʹม׵͢Δςʔϒϧ
    εϓϥΠτɺύϨοτ
    ͔Β3(#"ͷϐΫηϧσʔλ
    ʹม׵

    View full-size slide

  111. ϐΫηϧσʔλ͸ಘΒΕ͕ͨ
    Ͳ͏΍ͬͯϒϥ΢βʹදࣔ͢Δ͔

    View full-size slide

  112. const canvas = document.querySelector("canvas");
    const ctx = canvas.getContext("2d");
    Module.NES = { ctx, canvas, image: ctx.createImageData(256, 240) };
    mergeInto(LibraryManager.library, {
    canvas_render: function (ptr, len) {
    Module.NES.buf = new Uint8Array(Module.HEAPU8.buffer, ptr, len);
    Module.NES.image.data.set(Module.NES.buf);
    Module.NES.ctx.putImageData(Module.NES.image, 0, 0);
    },
    })
    +BWB4DSJQUଆͷॲཧ
    FNTDSJQUFOΛ࢖༻͍ͯ͠Δ৔߹
    NFSHF*OUPΛ࢖༻ͯ͠+4ؔ਺Λ
    3VTUଆʹެ։Ͱ͖Δ

    View full-size slide

  113. const canvas = document.querySelector("canvas");
    const ctx = canvas.getContext("2d");
    Module.NES = { ctx, canvas, image: ctx.createImageData(256, 240) };
    mergeInto(LibraryManager.library, {
    canvas_render: function (ptr, len) {
    Module.NES.buf = new Uint8Array(Module.HEAPU8.buffer, ptr, len);
    Module.NES.image.data.set(Module.NES.buf);
    Module.NES.ctx.putImageData(Module.NES.image, 0, 0);
    },
    })
    +BWB4DSJQUଆͷॲཧ
    3VTUଆ͔ΒϐΫηϧσʔλͷ
    ϙΠϯλͱ௕͞Λ΋Βͬͯ
    *NBHF%BUBʹηοτ

    View full-size slide

  114. extern "C" {
    fn canvas_render(ptr: *const u8, len: usize);
    }
    impl Renderer {
    pub fn render(
    &mut self,
    background: &BackgroundField,
    sprites: &SpritesWithCtx) {
    // …লུ…
    unsafe {
    canvas_render(self.buf.as_ptr(), self.buf.len());
    }
    }
    3VTU XBTN
    ଆͷॲཧ
    ͜Μͳ;͏ʹݺ΂Δ όοϑΝͷϙΠϯλͱ௕͞Λ
    ڭ͑ͯ͋͛Δ

    View full-size slide

  115. ͜ΕͰ73".ͷ಺༰Λ
    $BOWBTʹॻ͖ग़ͤͦ͏

    View full-size slide

  116. ͋ͱ͸$16ͱͷಉظͳͲ
    λΠϛϯάपΓ

    View full-size slide

  117. ͦͷલʹ116ͷϝϞϦۭؒͷ
    ஫ҙ఺Λ͝঺հ
    ׂ
    Ѫ

    View full-size slide

  118. 116%"5"͔Β116ͷϝϞϦۭؒͷσʔλΛ$16͔ΒϦʔυͰ͖Δ͕
    116಺෦ʹ͸ϦʔυόοϑΝ͕ೖ͍ͬͯͯ116͔Βͷσʔλग़ྗ̍αΠΫϧ஗ΕΔ
    ͨͿΜҟͳΔΫϩοΫͷόε
    Λ·͙ͨͨΊ'*'0ΛೖΕͯಉظΛͱͬͯΔ
    ͨͩ͠ɺεϓϥΠτ3".ɺύϨοτςʔϒϧ͸আ͘
    ʢ΍΍͍͜͠ʜʣ
    ͜Ε͸ʢଟ෼ʣεϓϥΠτ3".ɺύϨοτςʔϒϧ͸116ͷ಺෦ʹߏ੒͞Ε͍ͯͯ
    όεΛ·͍ͨͰ͍ͳ͍ʢ$16όε௚݁ʣ͡Όͳ͍͔ͱਪଌ
    ΤϛϡϨʔλ࡞ऀ͸͜ΕΛݟམͱ͢ͱপʹ͸·Δ
    116ͷϝϞϦۭؒ஫ҙ఺
    ׂ
    Ѫ

    View full-size slide

  119. 116ͷඳըλΠϛϯά

    View full-size slide

  120. MJOFQJYFM
    جຊతʹ͸116DZDMFͰQJYFMͣͭඳը
    ࠨ͔Βը໘ͷӈ୺ʹ
    QJYFMͣͭඳը͍ͯ͘͠
    EJTQMBZ
    116ͷඳըλΠϛϯά

    View full-size slide

  121. MJOFQJYFM
    ࣍ͷϥΠϯ΁ͷඳը४උΛؚΊΔͱMJOF͋ͨΓαΠΫϧඞཁ
    ࣍ͷϥΠϯ΁ͷ४උ
    ը໘ӈ୺·Ͱ౸ୡͨ͠Β
    ࣍ͷϥΠϯͷࠨ୺ʹ໭Δ
    ʢIWMBOL

    EJTQMBZ
    116ͷඳըλΠϛϯά

    View full-size slide

  122. MJOFQJYFM
    ը໘ͷӈԼ୺ʹ౸ୡ MJOF෼
    ͨ͠Βը໘෼ͷඳը͕׬ྃ
    EJTQMBZ MJOF
    116ඳըλΠϛϯά

    View full-size slide

  123. MJOFQJYFM
    EJTQMBZ
    ࣍ͷඳըͷͨΊʹઌ಄΁໭Δ
    ͜ͷͨΊͷظؒΛͱݴ͍
    MJOF෼ͷ࣌ؒΛཁ͢Δ
    Ұը໘ͷߋ৽ʹ͸
    Y αΠΫϧ
    ඞཁͱͳΔ
    ͢ͳΘͪ
    7CMBOL
    ը໘ͷӈԼ୺ʹ౸ୡ MJOF෼
    ͨ͠Βը໘෼ͷඳը͕׬ྃ
    116ඳըλΠϛϯά

    View full-size slide

  124. MJOFQJYFM
    ͜ͷαΠΫϧΛඵؒʹճ '14
    ܁Γฦ͢͜ͱͰ
    Ωϟϥ΍എܠ͕ͳΊΒ͔ʹಈ͖ήʔϜͱͯ͠੒ཱ͢Δ
    EJTQMBZ MJOF
    116ඳըλΠϛϯά

    View full-size slide

  125. 116ͷσʔλߋ৽ͷ੍໿
    ΤϛϡϨʔλ࡞ऀʹ͸
    ͋·Γؔ܎ͳ͍͔΋

    View full-size slide

  126. EJTQMBZ
    ඳըதʹ73".Λॻ͖׵͑Δͱը໘͕ΈͩΕͯ͠·͏
    ඳըத
    116ͷσʔλߋ৽ͷ੍໿

    View full-size slide

  127. ඳըΛߦ͍ͬͯͳ͍7CMBOLதʹ73".Λॻ͖׵͑Δ
    $16͸116εςʔλεϨδελ·ͨ͸/.*ʹͯ
    7MBOLͰ͋Δ͜ͱΛ஌Δ͜ͱ͕Ͱ͖Δ
    EJTQMBZ
    7CMBOLத
    116ͷσʔλߋ৽ͷ੍໿

    View full-size slide

  128. pub fn run(&mut self, cycle: usize, nmi: &mut bool, mmc: &Mmc) -> bool {
    let cycle = self.cycle + cycle;
    if cycle < 341 {
    self.cycle = cycle;
    return false;
    }
    if self.line == 0 {
    self.background.clear();
    }
    self.cycle = cycle - 341;
    self.line = self.line + 1;
    if self.line <= 240 && self.line % 8 == 0 {
    self.background.build_line(
    &self.ctx.vram,
    &self.ctx.cram,
    &self.ctx.palette,
    (tile_x, tile_y),
    );
    }
    // …লུ…
    }
    116ͷ࣮૷
    116αΠΫϧ਺ΛՃࢉ͍͖ͯ͠
    MJOF׬͔ྃͨ͠Λ൑ఆ

    View full-size slide

  129. pub fn run(&mut self, cycle: usize, nmi: &mut bool, mmc: &Mmc) -> bool {
    let cycle = self.cycle + cycle;
    if cycle < 341 {
    self.cycle = cycle;
    return false;
    }
    if self.line == 0 {
    self.background.clear();
    }
    self.cycle = cycle - 341;
    self.line = self.line + 1;
    if self.line <= 240 && self.line % 8 == 0 {
    self.background.build_line(
    &self.ctx.vram,
    &self.ctx.cram,
    &self.ctx.palette,
    (tile_x, tile_y),
    );
    }
    // …লུ…
    }
    116ͷ࣮૷
    ඳը۠ؒͰ͋Ε͹
    ϥΠϯຖʹഎܠΛ
    ૊Έཱ͍ͯͯ͘
    MJOFd

    View full-size slide

  130. pub fn run(&mut self, cycle: usize, nmi: &mut bool, mmc: &Mmc) -> bool {
    //…লུ…
    if self.line == 241 {
    self.registers.set_vblank();
    if self.registers.is_irq_enable() {
    *nmi = true;
    }
    }
    if self.line >= 262 {
    self.registers.clear_vblank();
    self.line = 0;
    self.sprites = build_sprites(
    &self.ctx.cram,
    &self.ctx.sprite_ram,
    &self.ctx.palette,
    );
    return true;
    }
    false
    }
    116ͷ࣮૷
    ׂΓࠐΈ༗ޮͰ͋Ε͹WCMBOL
    ࣌ʹ/.*ΛΞΫςΟϒʹઃఆ
    7#MBOLϑϥάΛηοτ
    MJOF

    View full-size slide

  131. pub fn run(&mut self, cycle: usize, nmi: &mut bool, mmc: &Mmc) -> bool {
    //…লུ…
    if self.line == 241 {
    self.registers.set_vblank();
    if self.registers.is_irq_enable() {
    *nmi = true;
    }
    }
    if self.line >= 262 {
    self.registers.clear_vblank();
    self.line = 0;
    self.sprites = build_sprites(
    &self.ctx.cram,
    &self.ctx.sprite_ram,
    &self.ctx.palette,
    );
    return true;
    }
    false
    }
    116ͷ࣮૷
    ϥΠϯͰҰը໘෼ͷ
    ඳը͕׬੒
    MJOF

    View full-size slide

  132. ͋ͱ͸$16ͱ116ɺඳըͷಉظΛ
    ͲͷΑ͏ʹͱΔ͔

    View full-size slide

  133. ٯࢉͯ͘͠ͱྑͦ͞͏

    View full-size slide

  134. ϑΝϛίϯ͸'14ɺ͢ͳΘͪNTຖʹ116͕ߋ৽ͨ͠
    ը໘σʔλΛ࡞੒Ͱ͖Ε͹ྑ͍
    લड़ͨ͠Α͏ʹը໘ͷߋ৽͸ 116αΠΫϧ
    ͳͷͰ
    NTຖʹ116͕ը໘ੜ੒͢Δ·Ͱ
    ໿ YαΠΫϧ
    $16Λ࣮ߦͯ͠΍Ε͹Α͍
    116ͷαΠΫϧ͸$16ͷഒ଎ʢഒͷΫϩοΫ͕ೖྗʣ
    $16ͱ116ͷಉظ

    View full-size slide

  135. ࣌ؒ
    NT NT
    ը໘෼ͷσʔλ͕
    Ͱ͖Δ·Ͱ
    $16116Λ࣮ߦ
    ը໘෼ͷσʔλ͕
    Ͱ͖Δ·Ͱ
    $16116Λ࣮ߦ
    ը໘෼ͷσʔλ͕
    Ͱ͖Δ·Ͱ
    $16116Λ࣮ߦ
    ඳը ඳը ඳը
    ͜ΜͳΠϝʔδͰ࣮ߦ͍ͨ͠
    NT
    $16ͱ116ͷಉظ

    View full-size slide

  136. SFRVFTU"OJNBUJPO'SBNFΛ࢖͍͍ͨ
    '14Ͱಈ࡞͢ΔΑ͏ʹ͍͍ײ͡ʹ͕Μ͹ͬͯ͘ΕΔ΍ͭ

    View full-size slide

  137. void emscripten_set_main_loop(
    em_callback_func func,
    int fps,
    int simulate_infinite_loop)
    FNTDSJQUFOΛ࢖༻͍ͯ͠Δ৔߹͍͕ͭ͜࢖͑Δ
    ୈೋҾ਺ʹΛηοτ͢ΔͱΛ
    ࢖ͬͯ͘ΕΔ
    SFRVFTU"OJNBUJPO'SBNF
    FNTDSJQUFO@TFU@NBJO@MPPQ
    ୈࡾҾ਺Ληοτ͢ΔͱແݶϧʔϓΛ
    γϛϡϨʔτ

    View full-size slide

  138. MFUNBJO@MPPQcc\
    nes::run(&mut ctx);
    };
    externs::set_main_loop_callback(main_loop);
    pub fn run(ctx: &mut Context) {
    loop {
    // …লུ…
    let cycle: u16 = cpu::run(&mut ctx.cpu_registers, &mut cpu_bus, &mut ctx.nmi) as u16
    let is_ready = ctx.ppu.run((cycle * 3) as usize, &mut ctx.nmi, &ctx.mmc);
    if is_ready {
    if ctx.ppu.background.0.len() != 0 {
    ctx.renderer.render(&ctx.ppu.background.0, &ctx.ppu.sprites);
    }
    break;
    }
    }
    }
    ϝΠϯϧʔϓͷ࣮૷
    NTपظͰOFTSVOΛ࣮ߦ

    View full-size slide

  139. MFUNBJO@MPPQcc\
    nes::run(&mut ctx);
    };
    externs::set_main_loop_callback(main_loop);
    pub fn run(ctx: &mut Context) {
    loop {
    // …লུ…
    let cycle: u16 = cpu::run(&mut ctx.cpu_registers, &mut cpu_bus, &mut ctx.nmi) as u16
    let is_ready = ctx.ppu.run((cycle * 3) as usize, &mut ctx.nmi, &ctx.mmc);
    if is_ready {
    if ctx.ppu.background.0.len() != 0 {
    ctx.renderer.render(&ctx.ppu.background.0, &ctx.ppu.sprites);
    }
    break;
    }
    }
    }
    ϝΠϯϧʔϓͷ࣮૷
    ߋ৽ͨ͠ը໘ͷϐΫηϧσʔλͷ४උ͕
    Ͱ͖Δ·Ͱ$16ͱ116Λ࣮ߦ͢Δ
    $16ͷ࣮ߦαΠΫϧͷഒͷαΠΫϧΛ
    ౉͢ʢ116αΠΫϧ΁ͷม׵ʣOΛ࣮ߦ

    View full-size slide

  140. MFUNBJO@MPPQcc\
    nes::run(&mut ctx);
    };
    externs::set_main_loop_callback(main_loop);
    pub fn run(ctx: &mut Context) {
    loop {
    // …লུ…
    let cycle: u16 = cpu::run(&mut ctx.cpu_registers, &mut cpu_bus, &mut ctx.nmi) as u16
    let is_ready = ctx.ppu.run((cycle * 3) as usize, &mut ctx.nmi, &ctx.mmc);
    if is_ready {
    if ctx.ppu.background.0.len() != 0 {
    ctx.renderer.render(&ctx.ppu.background.0, &ctx.ppu.sprites);
    }
    break;
    }
    }
    }
    ϝΠϯϧʔϓͷ࣮૷
    Ұը໘෼४උ͕Ͱ͖ͨΒϨϯμϦϯά

    View full-size slide

  141. ͜͜·Ͱ͕࣮૷Ͱ͖Ε͹
    )FMMP 8PSME͕ඳըͰ͖ͦ͏

    View full-size slide

  142. )&--0 803-%ͷαϯϓϧίʔυ
    ΛݟͯΈΔ

    View full-size slide

  143. IUUQIQWFDUPSDPKQBVUIPST7"OFTTBNQMFIUNMΑΓ
    )&--0 803-%

    View full-size slide

  144. )FMMP 8PSME
    char NesMain()
    {
    const char palettes[] = {
    0x0f, 0x00, 0x10, 0x20,
    0x0f, 0x06, 0x16, 0x26,
    0x0f, 0x08, 0x18, 0x28,
    0x0f, 0x0a, 0x1a, 0x2a
    };
    const char string[] = "HELLO, WORLD!";
    char i;
    *(char*)0x2000 = 0x00;
    *(char*)0x2001 = 0x00;
    *(char*)0x2006 = 0x3f;
    *(char*)0x2006 = 0x00;
    for (i = 0; i < 0x10; i ++)
    *(char*)0x2007 = palettes[i];
    *(char*)0x2006 = 0x21;
    *(char*)0x2006 = 0xc9;
    for (i = 0; i < 13; i ++)
    *(char*)0x2007 = string[i];
    *(char*)0x2000 = 0x08;
    *(char*)0x2001 = 0x1e;
    while (1);
    return 0;
    }

    View full-size slide

  145. char NesMain()
    {
    const char palettes[] = {
    0x0f, 0x00, 0x10, 0x20,
    0x0f, 0x06, 0x16, 0x26,
    0x0f, 0x08, 0x18, 0x28,
    0x0f, 0x0a, 0x1a, 0x2a
    };
    const char string[] = "HELLO, WORLD!";
    എܠύϨοτσʔλ
    ৭෼Λࢦఆ
    ॻ͖ࠐΉจࣈྻ
    )FMMP 8PSME

    View full-size slide

  146. *(char*)0x2000 = 0x00;
    *(char*)0x2001 = 0x00;
    *(char*)0x2006 = 0x3f;
    *(char*)0x2006 = 0x00;
    for (i = 0; i < 0x10; i ++)
    *(char*)0x2007 = palettes[i];
    ඳը΍ׂΓࠐΈΛېࢭ
    Y' YΛYʹॻ͖ࠐΉ
    ͜ͱͰ116ΞυϨεY'Λࢦఆ
    ͭ·ΓഎܠύϨοτςʔϒϧྖҬ
    YʹσʔλΛॻ͖͜ΜͰ͍͘͜ͱͰ
    ઌʹࢦఆͨ͠Y'͔ΒॱʹQBMFUUTͷσʔλΛసૹ͍ͯ͘͠
    116ΞυϨε͸σʔλ͕ॻ͖ࠐ·ΕΔͨͼʹ116ଆͰࣗಈΠϯΫϦϝϯτ͞ΕΔ

    ͜ΕͰύϨοτσʔλͷసૹ͸0,
    )FMMP 8PSME

    View full-size slide

  147. *(char*)0x2006 = 0x21;
    *(char*)0x2006 = 0xc9;
    for (i = 0; i < 13; i ++)
    *(char*)0x2007 = string[i];
    *(char*)0x2000 = 0x08;
    *(char*)0x2001 = 0x1e;
    while (1);
    return 0;
    }
    Y Y$ΛYʹॻ͖ࠐΉ
    ͜ͱͰ116ΞυϨεY$Λࢦఆ
    Yʹॻ͖ࠐΉ͜ͱͰ
    Y$ʙʹA)&--0 803-%A
    Λసૹ
    ඳը։࢝
    ͜ͷαϯϓϧ͸Ұ౓ը໘Λඳըͨ͠Β
    ߋ৽͞Εͳ͍ͷͰແݶϧʔϓ
    )FMMP 8PSME

    View full-size slide

  148. ͜͜·ͰͰΑ͏΍͘
    )&--0 803-%

    View full-size slide

  149. ଞͷ30.Λಈ͔͢ʹ͸·ͩ·ͩ
    ػೳΛ࣮૷͠ͳͯ͘͸ͳΒͳ͍

    View full-size slide

  150. 0x2000ʙ0x23BF 0x03C0 ωʔϜςʔϒϧ0
    0x23C0ʙ0x23FF 0x0040 ଐੑςʔϒϧ0
    0x2400ʙ0x27BF 0x03C0 ωʔϜςʔϒϧ1
    0x27C0ʙ0x27FF 0x0040 ଐੑςʔϒϧ1
    0x2800ʙ0x2BBF 0x03C0 ωʔϜςʔϒϧ2
    0x2BC0ʙ0x2BFF 0x0040 ଐੑςʔϒϧ2
    0x2C00ʙ0x2FBF 0x03C0 ωʔϜςʔϒϧ3
    0x2FC0ʙ0x2FFF 0x0040 ଐੑςʔϒϧ3
    116ͷϝϞϦϚοϓΛݟ௚͢ͱҎԼͷΑ͏ʹωʔϜςʔϒϧͱ
    ଐੑςʔϒϧͷηοτΛͭʢ͢ͳΘͪը໘෼ʣ࣋ͯΔΑ͏ʹͳ͍ͬͯΔ
    116ͷϝϞϦϚοϓ ࠶

    View full-size slide

  151. ը໘෼ͷςʔϒϧ͸ҎԼͷΑ͏ͳ഑ஔʹͳ͍ͬͯΔ
    ωʔϜଐੑςʔϒϧ
    YdY''
    ωʔϜଐੑςʔϒϧ
    YdY''
    ωʔϜଐੑςʔϒϧ
    YdY#''
    ωʔϜଐੑςʔϒϧ
    Y$dY'''
    116ͷωʔϜଐੑςʔϒϧͷ഑ஔ

    View full-size slide

  152. ԣεΫϩʔϧήʔϜͷྫ

    View full-size slide

  153. ҎԼͷΑ͏ʹTDSPMM@YΛࢦఆ͢Δ͜ͱͰσΟεϓϨΠʹ੾Γग़͢ྖҬΛมߋͰ͖Δ
    ωʔϜ
    ଐੑςʔϒϧ
    YdY''
    ωʔϜ
    ଐੑςʔϒϧ
    YdY''
    σΟεϓϨΠʹ͸ҎԼͷ෦෼͕੾Γग़͞Εͯ
    දࣔ͞ΕΔ
    TDSPMM@Y
    εΫϩʔϧͱදࣔྖҬͷؔ܎

    View full-size slide

  154. εΫϩʔϧؔ͢ΔϨδελ͸ͭ
    ׂ
    Ѫ

    View full-size slide

  155. ΞυϨε ֓ཁ
    Y
    എܠεΫϩʔϧΦϑηοτ
    ճϥΠτΛߦ͏͜ͱͰ9ɺ:ͷॱʹεΫϩʔϧ஋͕ઃఆ͞ΕΔ
    1164$30--Ϩδελ
    αΠζ͕CJUͳͷͰd·ͰͷεΫϩʔϧ͕ઃఆͰ͖Δ
    ͜ͷͻͱͭͷϨδελͰYํ޲ɺZํ޲྆ํઃఆͰ͖ΔΑ͏ʹͳ͍ͬͯΔ
    ࠷ॳͷॻ͖ࠐΈ͕Yํ޲ɺೋճ໨ͷॻ͖ࠐΈ͕Zํ޲ͱͳΔ
    QYͣͭεΫϩʔϧ͍ͨ͠৔߹͸͜ͷϨδελΛ੍ޚ͢Δ
    ͔͠͠ɺ͜ͷϨδελ͚ͩͰ͸QYҎ্ͷεΫϩʔϧ͸ෆՄ
    ׂ
    Ѫ

    View full-size slide

  156. 116$53-Ϩδελ
    ΞυϨε ֓ཁ
    Y
    CJU આ໌
    ʜ ʜলུʜ
    ωʔϜςʔϒϧࢦఆ
    116$53-Ϩδελ Y
    ͷCJU͸ωʔϜςʔϒϧΛࢦఆ͢Δ͜ͱ͕Ͱ͖Δ
    ωʔϜ
    ଐੑςʔϒϧ
    ωʔϜ
    ଐੑςʔϒϧ
    ωʔϜ
    ଐੑςʔϒϧ
    ωʔϜ
    ଐੑςʔϒϧ
    ྫ͑͹ωʔϜςʔϒϧࢦఆ͕CͰ͋Ε͹͜ͷςʔϒϧ͕ࢦఆ͞Εͨ͜ͱʹͳΓ
    Yํ޲ʹQY෼εΫϩʔϧ͕Φϑηοτͨ͜͠ͱͱಉ౳ͱͳΔ
    ઌͷ1164$30--ͱ߹ΘͤΕ͹
    QYҎ্ͷεΫϩʔϧ͕Մೳ
    ׂ
    Ѫ

    View full-size slide

  157. ͜ΕΒΛ࢖͏ͱ໘ന͍දݱ͕Մೳʹ

    View full-size slide

  158. ϥελεΫϩʔϧ

    View full-size slide

  159. ඳըͷ్தͰεΫϩʔϧ஋Λௐ੔͢Δ͜ͱͰը໘ͷ్த͔ΒεΫϩʔϧ͕Մೳ
    εΫϩʔϧ଎౓Λม͑Δ͜ͱͰͦΕͧΕҧͬͨ଎౓ͰεΫϩʔϧͤ͞Δ͜ͱ΋Մೳ
    ϥελεΫϩʔϧ

    View full-size slide

  160. ͜͜·Ͱઆ໌ͨ͠ͷ͸എܠͰ͕͢ɺΩϟϥΫλʔΛಈ͔͢ʹ͸
    εϓϥΠτͱͯ͠ඳը͢Δඞཁ͕͋Δ
    എܠ εϓϥΠτ
    എܠ͸YͷλΠϧΛYݸ
    ը໘ʹෑ͖٧ΊͯεΫϩʔϧ౳Ͱ
    ಈ͔͢͜ͱ͕Ͱ͖Δ
    εϓϥΠτͰ͋Ε͹YZࣗ༝ʹઃఆՄೳ
    8PYJBOHOJÁPOJÁP.PKPO5XJOT
    εϓϥΠτ

    View full-size slide

  161. εϓϥΠτͷσʔλ͸Ͳ͜ʹॻ͔͘

    View full-size slide

  162. 116͸εϓϥΠτ༻ͷྖҬεϓϥΠτ3".Λ͍࣋ͬͯΔ
    116ͷϝϞϦϚοϓʹ͸දݱ͞Ε͍ͯͳ͍͓ͦ͠Β͘116಺෦ͷྖҬʁ
    ΞυϨε ֓ཁ
    Y
    εϓϥΠτϝϞϦΞυϨε
    YΛܦ༝ͯ͠εϓϥΠτϝϞϦ΁ϦʔυϥΠτ͢ΔϏοτΞυϨεΛࢦఆ
    Y
    εϓϥΠτϝϞϦσʔλ
    YʹΑͬͯࢦఆ͞ΕͨεϓϥΠτϝϞϦΞυϨεʹ͍ͨͯ͠ϦʔυϥΠτΛߦ͏
    ΞΫηε͢Δͨͼʹ౓ʹεϓϥΠτϝϞϦΞυϨε͸ΠϯΫϦϝϯτ
    ͞ΕΔɻ
    ΞΫηεํ๏͸116"%%3116%"5" YY
    ͱ΄΅ಉ͡
    ҟͳΔ఺͸εϓϥΠτ3".ͷۭؒ͸CJUͰදݱͰ͖ΔͷͰ
    ΞυϨεΛઃఆ͢ΔͨΊʹ̎ճॻ͖ࠐΉඞཁ͸ͳ͍
    #ZUF
    εϓϥΠτ3".

    View full-size slide

  163. εϓϥΠτͭʹରͯ͠ҎԼͷ#ZUFͷઃఆΛ͍࣋ͬͯΔ
    #ZUF ֓ཁ
    :࠲ඪ

    εϓϥΠτΠϯσοΫε
    ΩϟϥΫλʔ30.಺ͷεϓϥΠτͷԿ൪໨ͷεϓϥΠτΛద༻͢Δ͔Λࢦఆ͢Δ

    9࠲ඪ
    CJU આ໌
    ਨ௚ํ޲൓స൓స͠ͳ͍൓స͢Δ
    ਫฏํ޲൓స൓స͠ͳ͍൓స͢Δ
    දࣔ༏ઌॱҐεϓϥΠτΛ༏ઌഎܠΛ༏ઌ
    ༧໿

    ύϨοτ൪߸CύϨοτCύϨοτ
    CύϨοτCύϨοτ
    εϓϥΠτ3".͸#ZUFͳͷͰηοτͰ͖Δ
    ࠷େεϓϥΠτ
    εϓϥΠτ3".

    View full-size slide

  164. εϓϥΠτʹؔ͢ΔϢχʔΫͳ࢓༷

    View full-size slide

  165. εϓϥΠτώοτ
    ʢ௨শʰര஄ʱʣ

    View full-size slide

  166. ΞυϨε ֓ཁ
    Y
    CJU આ໌
    7CMBOL࣌ʹ
    εϓϥΠτώοτ࣌ʹ
    εΩϟϯϥΠϯεϓϥΠτ਺ɹݸҎԼݸҎ্
    3FTFSWFE
    εϓϥΠτ̌ώοτ
    εϓϥΠτ3".ͷઌ಄ʹઃఆ͞ΕͨεϓϥΠτ͕
    ϥΠϯόοϑΝʹల։͞ΕΔͱ116Ϩδελ Y

    ͷʮεϓϥΠτ̌ώοτʯϑϥάཱ͕ͭVOΛ࣮ߦ

    View full-size slide

  167. ࣮͸͜͜ʹಁ໌ͳ̌ര஄͕഑ஔ͞Ε͍ͯΔ
    8PYJBOHOJÁPOJÁP.PKPO5XJOT
    εϓϥΠτ̌ώοτ

    View full-size slide

  168. ʮεϓϥΠτ̌ώοτʯϑϥάΛݕग़͔ͯ͠Β
    εΫϩʔϧॲཧΛ։࢝͢Δ͜ͱʹΑΓ
    ݻఆϔομΛ࣮ݱ͍ͯ͠Δ
    ج४ͱͳΔεϓϥΠτʢ̌ര஄ʣ
    ͸͜͜ʹઃஔͯ͋͠Δ
    8PYJBOHOJÁPOJÁP.PKPO5XJOT
    εϓϥΠτ̌ώοτ

    View full-size slide

  169. εϓϥΠτͷ੍໿

    View full-size slide

  170. ࣮͸εϓϥΠτ͸ಉҰϥΠϯ্ʹͭ·Ͱ͔͠഑ஔͰ͖ͳ͍
    116͸ϥΠϯόοϑΝΛ͓࣋ͬͯΓ
    ϥΠϯຖʹεϓϥΠτͱഎܠͷ߹੒Λߦ͍ඳը͍ͯ͠Δ
    ͜ͷॲཧ͸ίετ͕ߴ͘࠷େͭ·Ͱ͔͠߹੒Ͱ͖ͳ͍Β͍͠
    ౰࣌ͷϝϞϦͱίετͷؔ܎͔Β
    ϑϨʔϜόοϑΝʹ͸Ͱ͖ͳ͔ͬͨΜͩͱਪଌ
    ΞυϨε ֓ཁ
    Y
    CJU આ໌
    ʜ ʜ
    εΩϟϯϥΠϯεϓϥΠτ਺ɹݸҎԼݸҎ্
    ʜ ʜ
    ͜Ε͸্ه੍໿Λݕग़͢ΔͨΊͷػߏ
    ͕ͩɺόάͬͯΔͱͷӟ΋͋Γ
    Ͳͷఔ౓࢖༻͞Ε͍ͯͨͷ͔͸ෆ໌
    εϓϥΠτͷ੍໿

    View full-size slide

  171. ൃੜ͢Δ໰୊ͱରࡦʢະݕূʣ

    View full-size slide

  172. ࠶ݱ؀ڥ͕ͳ͍ͷͰະݕূͰ͕͢ʜ
    υϥΰϯΫΤετͰ͸֗ͷதͰ̐ਓͷύʔςΟͱଜਓ͕
    ԣҰ௚ઢʹฒͿͱϥΠϯ্ͷεϓϥΠτ਺͕ͱͳΓ
    ύʔςΟϝϯόʔ΋͘͠͸ଜਓ͕ফ͑Δ
    ͦͷͨΊɺιϑτ΢ΣΞͰਓΛߴ଎ʹදࣔඇදࣔΛ܁Γฦ͢͜ͱͰ
    Ωϟϥ͕఺໓ͯ͠͠·͏΋ͷͷಉ࣌ʹදࣔ͢Δ͜ͱΛՄೳʹͨ͠
    ͱ͍͏࿩͕͋͠ΔΒ͍͠ʢཁݕূʣ
    ΩϟϥεϓϥΠτͳͷͰ
    ਓͳΒͿͱεϓϥΠτʹ
    ͳͬͯ͠·͏
    ଜਓ
    ਓύʔςΟ
    ൃੜ͢Δ໰୊ͱରࡦʢະݕূʣ

    View full-size slide

  173. Ͱ΋ɺ͓Ε͸Ͱ͔͍ͬϘεΈͨ͜ͱ͕͋Δͧʂ
    ͱ͍͏ํ΋͍Δ͔΋

    View full-size slide

  174. IUUQTXXXZPVUVCFDPNXBUDI W1(1EP1T3ΑΓ
    εϓϥΠτͰ͸ͳ͘
    എܠͰඳը
    ͜Ε͸εϓϥΠτͰ͸ͳ͘എܠͰϘεΛදݱͯ͠ΔͬΆ͍
    εϓϥΠτͰ͋Ε͹ෳࡶͳഎܠͷ্ʹ
    ߹੒ʢॏͳΓ͕දݱʣ͞Εͯදࣔ͞ΕΔ͕
    എܠͰఢΛදݱͯ͠͠·͏ͱॏͶΔ͜ͱ͕Ͱ͖ͳ͍
    ͳͷͰɺഎܠ͸ਅͬࠇʹͯ͠ΔͱࢥΘΕΔ
    ௨ৗഎܠͱͯ͠ඳը͢ΔͰ͋Ζ͏
    ଍৔ΛεϓϥΠτͱͯ͠ඳը
    ͔ͭӈ͔Βࠨ΁Ҡಈͤ͞Δ͜ͱ
    ʹΑΓυϥΰϯ͕௥ͬͯ͘ΔΑ͏ʹ
    දݱ
    υϥΰϯͷ্ԼҠಈ͸
    എܠεΫϩʔϧͰ࣮ݱ
    ͜͏͍͏΍ͭ

    View full-size slide

  175. εϓϥΠτͷసૹύϑΥʔϚϯε

    View full-size slide

  176. ͨͱ͑͹εϓϥΠτ3".#ZUFΛద౰ͳ஋ͰຒΊΔ
    ؆୯ͳॲཧΛߟ͑ͯΈΔ
    ldy $FF # 2cycle
    copysprites:
    sty $2004 # 4cycle
    dey # 2cycle
    bne copysprites # 2cycle
    YDZDMF
    dΛεϓϥΠτ3".
    ʹॻ͖ࠐΉ
    εϓϥΠτͷసૹύϑΥʔϚϯε

    View full-size slide

  177. εϓϥΠτ΋എܠಉ༷7CMBOLͷظؒʹసૹ͢Δඞཁ͕͋Δ
    7CMBOLͷظؒ͸$16ͷαΠΫϧ਺ʹ׵ࢉ͢Δͱ
    Y$ZDMF
    116DMPDLMJOF
    7CMBOLظؒʹ૬౰͢ΔMJOF਺
    116ΫϩοΫ͸
    $16ΫϩοΫͷഒͳͷͰ
    ઌͷࢼࢉͰ$ZDMFͳͷͰʜ
    ͘͢͝୯७ͳॲཧͰ΋΄ͱΜͲͷ7CMBOLظؒΛઐ༗ͯ͠͠·͏ʜ
    εϓϥΠτͷసૹύϑΥʔϚϯε

    View full-size slide

  178. %."
    %JSFDUNFNPSZBDDFTT

    View full-size slide

  179. ௨ৗ$16͕ϩʔυ໋ྩ΍ετΞ໋ྩΛ࢖༻ͯ͠ϝϞϦؒͷ
    σʔλసૹ౳Λߦ͏ͱ͜ΖΛɺ$16Λհͣ͞σʔλసૹ
    ͯ͘͠ΕΔपลػೳʢϖϦϑΣϥϧʣ
    ૊ΈࠐΈͳͲ௿εϖοΫͳ$16Ͱ΋࢖͍ํ͕͸·Ε͹
    ύϑΥʔϚϯεΛҾ্͖͛ΒΕΔʢ͔΋͠Εͳ͍ʣ௒ॏ
    ཁͳػߏ
    %."ͱ͸

    View full-size slide

  180. ͜Ε·Ͱʹࣗ෼͕ݟͨͷ͸
    εΩϟφϝϞϦͷసૹ΍ϝϞϦϓϦϯλ
    &UFISOFUίϯτϩʔϥϝϞϦͷసૹͳͲ
    ͨͱ͑͹%."͕ͳ͍ͱҎԼͷΑ͏ͳखॱʹͳͬͨΓ͢Δ
    $16
    εΩϟφ
    όε
    3".
    ᶃεΩϟφ͔ΒϦʔυ
    ᶄ3".΁ϥΠτ
    %."ͱ͸

    View full-size slide

  181. εΩϟφϝϞϦͷసૹྫ
    %."͕͋Ε͹ҎԼͷΑ͏ʹҰؾʹసૹͰ͖ͨΓ͢Δ
    ʢ৔߹͕͋Δʣ
    $16
    εΩϟφ
    όε
    3".
    ᶃεΩϟφ͔Β3".
    ΁సૹ
    %."ͱ͸

    View full-size slide

  182. /&4ͷ৔߹Y൪஍ʹ஋Λॻ͖ࠐΉ͜ͱͰ%."͕ىಈ͠
    ॻ͖ࠐΜͩ஋Λ্ҐΞυϨεɺYΛԼҐΞυϨεͱͨ͠ΞυϨ
    εΛى఺ʹ#ZUFΛεϓϥΠτ3".ʹసૹ͢Δ
    ΋͏ͪΐ͍۩ମతʹ͍͏ͱ
    ྫ͑͹YʹYΛॻ͖ࠐΜͩ৔߹
    Y͔ΒY''·Ͱͷ#ZUF͕
    εϓϥΠτ3".ʹసૹ͞ΕΔ
    సૹ͸$16αΠΫϧͰ׬ྃ͢ΔͷͰ
    $16Ͱ#ZUFసૹ͢ΔΑΓߴ଎ʹసૹͰ͖Δ
    ʢόε͕ઐ༗͞ΕΔͷͰ$16͸ͦͷؒఀࢭ͢Δʣ
    %."
    /&4ͷ%."͸͔ͳΓ௿ػೳ

    View full-size slide

  183. ίϯτϩʔϥ

    View full-size slide

  184. /&4ͷ৔߹Y൪஍ʹίϯτϩʔϥ͕഑ஔ͞Ε͍ͯΔ
    Y൪஍ʹY YΛॱʹॻ͖ࠐΉͱͦͷॠؒͷίϯτϩʔϥ
    ͷ֤εΠονͷঢ়ଶ͕ϥον͞ΕY൪஍ΛϦʔυ͢Δ͜ͱͰ
    ॱ࣍εΠονঢ়ଶΛಡΉ͜ͱ͕Ͱ͖Δ
    ॳճϦʔυ࣌͸"Ϙλϯͷঢ়ଶɺ࣍ͷϦʔυͰ#Ϙλϯͷঢ়ଶʜ
    ͱ͍ͬͨΑ͏ʹॱ࣍औಘ͢ΔͨΊશϘλϯͷঢ়ଶΛ஌Δʹ͸
    ߹ܭճͷϦʔυ͕ඞཁ
    Ϧʔυ ରԠϘλϯ
    "
    #
    4&-&$5
    45"35

    Լ

    ӈ
    ίϯτϩʔϥ
    ̎1͸Y

    View full-size slide

  185. ϒϥ΢βͰͷΤϛϡϨʔγϣϯ

    View full-size slide

  186. const convertKeyCode = keyCode => {
    switch (keyCode) {
    case 88:
    return 0x01; // X A
    case 90:
    return 0x02; // Z B
    case 65:
    return 0x04; // A SELECT
    case 83:
    return 0x08; // S START
    case 38:
    return 0x10; // ↑ ↑
    case 40:
    return 0x20; // ↓ ↓
    case 37:
    return 0x40; // ← ←
    case 39:
    return 0x80; // → →
    }
    };
    document.addEventListener("keydown", e => {
    buf[size - 1] |= convertKeyCode(e.keyCode);
    });
    document.addEventListener("keyup", e => {
    buf[size - 1] &= ~convertKeyCode(e.keyCode);
    });
    +BWB4DSJQUଆͷॲཧ
    LFZEPXOVQΠϕϯτΛ
    MJTUFO
    OFTϑΝΠϧͷத਎Λ౉ͨ͢Ίͷ
    όοϑΝͷ຤ඌʹΩʔೖྗΛ
    ௨஌͢ΔͨΊͷྖҬ#ZUF෼֬
    อͦ͜͠ʹঢ়ଶΛॻ͖ࠐΉ

    View full-size slide

  187. let main_loop = || {
    let key_state = buf[len - 1];
    keypad.update(key_state);
    // …লུ…
    };
    impl Keypad {
    pub fn new() -> Self {
    // …লུ…
    }
    pub fn update(&mut self, data: Data) {
    self.buffer = data;
    }
    pub fn write(&mut self, data: Data) {
    // …লུ…
    }
    pub fn read(&mut self) -> u8 {
    let v = (0x01 << self.addr) as u8;
    let ret = ((self.register & v) >> self.addr) as u8;
    self.addr += 1;
    ret
    }
    }
    3VTU XBTN
    ଆͷॲཧ
    ϝΠϯϧʔϓͰ+4͔Βड͚औͬͨ
    Ωʔͷঢ়ଶΛ൓ө
    Y͕Πʔυ͞ΕΔͨͼ
    " # 4&-&$5ʜͷॱʹ
    ஋Λฦ͢Α͏ʹ͓ͯ͘͠

    View full-size slide

  188. "16 α΢ϯυ

    ׂ
    Ѫ

    View full-size slide

  189. ϑΝϛίϯͷ৔߹"16 ΦʔσΟΦϓϩηογϯάϢχο
    τʣͱ%"$ σΟδλϧΞφϩάίϯόʔλ
    ͕$16ʹ
    ૊Έࠐ·Ε͍ͯΔ
    "16 α΢ϯυ

    νϟωϧ͸ۣܗ೾͕νϟωϧɺࡾ֯೾νϟωϧɺϊ
    Πζνϟωɺ%1$.νϟωϧͷνϟωϧ͕࢖༻Ͱ
    ͖ήʔϜͷԻ͸͜ͷνϟωϧͷ૊Έ߹ΘͤʹΑΓදݱ͞
    ΕΔ
    ׂ
    Ѫ

    View full-size slide

  190. IUUQTDPEFQFOJPHSFHIQFOYR8XR[
    Πϝʔδ͸͜ͷDPEFQFO͕Θ͔Γ΍͍͢
    "16 α΢ϯυ

    ׂ
    Ѫ

    View full-size slide

  191. ϨδελΛோΊΔ
    ׂ
    Ѫ

    View full-size slide

  192. ΞυϨε 38 ༻్
    Y 8 ۣܗ೾$)੍ޚϨδελ
    Y 8 ۣܗ೾$)੍ޚϨδελ
    Y 8 ۣܗ೾$)प೾਺Ϩδελ
    Y 8 ۣܗ೾$)प೾਺Ϩδελ
    Y 8 ۣܗ೾$)੍ޚϨδελ
    Y 8 ۣܗ೾$)੍ޚϨδελ
    Y 8 ۣܗ೾$)प೾਺Ϩδελ
    Y 8 ۣܗ೾$)प೾਺Ϩδελ
    Y 8 ࡾ֯೾੍ޚϨδελ
    Y" 8 ࡾ֯೾प೾਺Ϩδελ
    Y# 8 ࡾ֯೾प೾਺Ϩδελ
    "16ͷϨδελҰཡ
    ׂ
    Ѫ

    View full-size slide

  193. ΞυϨε 38 ༻్
    Y$ 8 ϊΠζ੍ޚϨδελ
    Y& 8 ϊΠζཚ਺Ϩδελ
    Y' 8 ϊΠζ࣌ؒϨδελ
    Y 8 %1$.੍ޚϨδελ
    Y 8 %1$.੍ޚϨδελ
    Y 8 %1$.੍ޚϨδελ
    Y 8 %1$.੍ޚϨδελ
    Y 38 Ի੠νϟωϧ੍ޚϨδελ
    Y 38 ϑϨʔϜΧ΢ϯλ
    "16ͷϨδελҰཡ
    ׂ
    Ѫ

    View full-size slide

  194. ۣܗ೾ΛΈ͍ͯ͘
    ׂ
    Ѫ

    View full-size slide

  195. Τϯϕϩʔϓ
    δΣωϨʔλ
    εΠʔϓ λΠϚʔ
    γʔέϯα
    ௕͞Χ΢ϯλ
    ۣܗ೾ͷߏ੒
    ׂ
    Ѫ

    View full-size slide

  196. ΞυϨε ֓ཁ
    Y
    CJU આ໌

    σϡʔςΟൺCC
    CC
    ࠶ੜ࣌ؒΧ΢ϯλΠωʔϒϧ
    ΤϯϕϩʔϓσΟηʔϒϧ
    ϘϦϡʔϜ·ͨ͸ΤϯϕϩʔϓσΟόΠμ
    σϡʔςΟൺ
    ݮਰͷ଎౓ͳͲΛ੍ޚ
    ۣܗ೾Ϩδελ
    ׂ
    Ѫ

    View full-size slide

  197. ΞυϨε ֓ཁ
    Y
    CJU આ໌
    εΠʔϓΠωʔϒϧ
    प೾਺มԽ଎౓
    प೾਺ͷมԽํ޲Լ্߱ঢ
    प೾਺มߋྔͷ৔߹มԽͳ͠
    प೾਺ͷ૿ݮΛ੍ޚ
    ۣܗ೾Ϩδελ
    ׂ
    Ѫ

    View full-size slide

  198. ΞυϨε ֓ཁ
    Y
    Y
    CJU આ໌
    ύϧελΠϚʔԼҐCJU
    CJU આ໌
    ΩʔΦϑΧ΢ϯλ
    ύϧελΠϚʔ্ҐCJU
    प೾਺ͱ࠶ੜ࣌ؒΛ੍ޚ
    ۣܗ೾Ϩδελ
    ׂ
    Ѫ

    View full-size slide

  199. Ͳ͏΍ͬͯΤϛϡϨʔτ͢Δ͔
    ׂ
    Ѫ

    View full-size slide

  200. 8FC"VEJP
    ׂ
    Ѫ

    View full-size slide

  201. class Oscillator {
    constructor(type) {
    const AudioContext = window.AudioContext || window.webkitAudioContext
    this.context = new AudioContext();
    this.oscillator = this.createOscillator({ kind: type });
    // …লུ…
    }
    createOscillator(options = {}) {
    const oscillator = this.context.createOscillator();
    // …লུ…
    return oscillator;
    }
    setPulseWidth(pulseWidth) {
    this.oscillator.setPeriodicWave(this.waves[`${pulseWidth}`]);
    }
    setFrequency(frequency) {
    this.oscillator.frequency.value = frequency;
    }
    changeFrequency(frequency) {
    this.oscillator.frequency.setValueAtTime(frequency, this.context.currentTime)
    }
    }
    +BWB4DSJQUଆͷॲཧ
    TFU1FSJPEJD8BWFͰ
    ΧελϜ೾ܗΛ࡞੒Ͱ͖Δ
    ׂ
    Ѫ

    View full-size slide

  202. mergeInto(LibraryManager.library, {
    start_oscillator: function (index) {
    Module.NES.oscs[index].start();
    },
    set_oscillator_frequency: function (index, freq) {
    Module.NES.oscs[index].setFrequency(freq);
    },
    change_oscillator_frequency: function (index, freq) {
    Module.NES.oscs[index].changeFrequency(freq);
    },
    set_oscillator_volume: function (index, volume) {
    Module.NES.oscs[index].setVolume(volume);
    },
    set_oscillator_pulse_width: function (index, width) {
    Module.NES.oscs[index].setPulseWidth(width);
    },
    }
    3VTU XBTN
    ଆ΁ͷϒϦοδ
    ࠶ͼNFSHF*OUPͰ
    3VTUଆ΁ެ։
    ׂ
    Ѫ

    View full-size slide

  203. ͋ͱ͸)[)[ͷपظͱ
    $16͔ΒͷΞΫηελΠϛϯά
    प೾਺΍ϘϦϡʔϜͷมಈ͕ൃੜ͢Δ
    ͷͰͦͷλΠϛϯάͰݺΜͰ΍Ε͹͍͍
    ׂ
    Ѫ

    View full-size slide

  204. pub fn update_counters(&mut self) {
    // …লུ…
    self.sweep_unit_counter += 1;
    self.change_frequency();
    }
    pub fn update_envelope(&mut self) {
    // …লུ…
    unsafe {
    set_oscillator_volume(self.index, self.get_volume());
    };
    }
    fn change_frequency(&self) {
    unsafe {
    change_oscillator_frequency(self.index, self.frequency);
    }
    }
    3VTU XBTN
    ଆͷॲཧ
    ׂ
    Ѫ

    View full-size slide

  205. ͜͜·ͰͰϑΝϛίϯຊମͷ
    ϋʔυ΢ΣΞ͸Ұ௨Γ࣮૷Ͱ͖ͨ͸ͣ

    View full-size slide

  206. 2͜ΕͰશͯͷ30.͕ಈ࡞͢Δ͔

    View full-size slide

  207. ..$
    NFNPSZNBOBHFNFOUDPOUSPMMFS

    View full-size slide

  208. Χηοτ಺ʹ..$ͱݺ͹ΕΔ
    ϝϞϦ؅ཧ༻ͷిࢠճ࿏Λ͍࣋ͬͯΔ
    Χηοτ͕͋Δ
    ͜ͷػߏʹΑΓϓϩάϥϜ30.࠷େLJ#
    ΩϟϥΫλʔ30.LJ#ͷ੍ݶ͸௒͑ΒΕΔ
    ..$

    View full-size slide

  209. ..$ʹΑΔϝϞϦͷϚοϐϯά৘ใ
    Λ.BQQFSͱݺͿ
    ..$

    View full-size slide

  210. .BQQFSͷҰ෦ ·ͩ΄͔ʹ΋͋Δ

    .BQQFS

    View full-size slide

  211. .BQQFS
    ࣮͸͍͕ͭ͜..$
    ҎԼ͸.BQQFSͷج൘

    View full-size slide

  212. ຊདྷϥΠτͰ͖ͳ͍Ydͷۭؒ
    ʹόϯΫ൪߸Λॻ͖ࠐΉ͜ͱͰ࠷େ,J#
    ·Ͱ30.Λ࢖༻͢Δ͜ͱ͕Ͱ͖Δ
    .BQQFS

    View full-size slide

  213. ͲΜͳճ࿏ʹͳͬͯΔ͔

    View full-size slide

  214. $)3
    30.
    $/
    )$

    ""
    ""
    %%
    8&
    )$ͰσʔλΛϥον͠
    ΞυϨεʹม׵
    ΩϟϥΫλʔ30.
    όΠφϦΧ΢ϯλ
    .BQQFSͷճ࿏

    View full-size slide

  215. impl Mmc {
    pub fn new(mapper: u8, bank: u8) -> Self {
    Mmc { bank, mapper }
    }
    pub fn set_bank(&mut self, bank: u8) {
    self.bank = bank;
    }
    pub fn create_chram_addr(&self, addr: u16) -> u16 {
    addr + (self.bank as u16) * 0x2000
    }
    }
    .BQQFSͷ࣮૷
    όϯΫͷઃఆ͔Β
    ΩϟϥΫλʔ30.΁ͷΞυϨε
    Λܭࢉͯ͠ฦ͢

    View full-size slide

  216. ରԠ30.Λ૿΍͢ʹ͸
    ֤ͭͭ͜͜.BQQFSͷରԠ͕ඞཁ

    View full-size slide

  217. ͜ΕΛ໢ཏ͢Δͱ͢΂ͯͷ
    30.͕ಈ࡞͢Δ͸ͣ

    View full-size slide

  218. ύϑΥʔϚϯε

    View full-size slide

  219. DISPNF

    8FC"TTFNCMZWT+BWB4DSJQU
    DISPNFDBOBSZ

    pSFGPY
    CJU

    pSFGPYEFWFMPQFSFEJUJPO
    C CJU

    TBGBSJ


    NT NT NT NT
    NT NT
    NT NT
    NT
    NT



    UJNF
    TNBMMFSJTCFUUFS
    8FC"TTFNCMZ CPLVXFCSVTUZOFT

    +BWB4DSJQU CPLVXFCqPXOFT

    8FC"VEJP$BOWBTΛσΟηʔϒϧʹͨ͠ঢ়ଶͰ
    ϝΠϯϧʔϓͷॲཧ࣌ؒճͷฏۉ஋Λൺֱ
    .BD#PPL"JS JODI &BSMZ
    ()[*OUFM$PSFJ(#.)[%%3
    HJLPOFT

    View full-size slide

  220. ͍͞͝ʹ
    !ϑΝϛίϯΤϛϡϨʔλ͸ҰਓͰ࣮૷͢Δͷʹ΋खࠒͳαΠζ
    !$16΍%."ɺׂΓࠐΈͳͲͷಈ࡞Λֶ΂Δ
    !ઌਓͷۤ࿑ͷยྡྷΛຯΘ͑Δ
    !ࣗ෼΋99ݴޠͰ΍ͬͯΈΔ͔ʂͱࢥͬͯ΋Β͑ͨΒخ͍͠Ͱ͢

    View full-size slide

  221. ͋Γ͕ͱ͏͍͟͝·ͨ͠✨

    View full-size slide