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

83c268781ec54605af1f7b866d7de3ad?s=47 bokuweb
September 07, 2018
37k

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

83c268781ec54605af1f7b866d7de3ad?s=128

bokuweb

September 07, 2018
Tweet

Transcript

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

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

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

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

  5. %&.0 IUUQTHJUIVCDPNCPLVXFCSVTUZOFT

  6. $16 31" 3*$0)੡ CJU.)[ 116 ϐΫνϟʔϓϩηοαϢχοτ31$ 30. ࠷େϓϩάϥϜ30.,J# ΩϟϥΫλ30.,J# 83".

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

    .)[ .)[ /.* CJU116CVT CJU$16CVT "16 ϑΝϛίϯ σΟεϓϨΠ α΢ϯυ ίϯτϩʔϥ ϑΝϛίϯͷϒϩοΫਤ
  8. ΤϛϡϨʔλΛ࡞Δʹ͸ ͜ΕΒͷσόΠεΛҰͭҰͭ ࣮૷͍ͯ͘͠ඞཁ͕͋Δ

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

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

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

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

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

  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ͷόε৴߸
  15. ΩϟϥΫλʔ 30. 116 $16 ϑΝϛίϯຊମ ϓϩάϥϜ 30. Χηοτ $16όεΛհͯ͠ Ϧʔυ͞ΕΔ

    116όεΛհͯ͠ Ϧʔυ͞ΕΔ Χηοτͱຊମͱͷόε઀ଓ
  16. ϓϩάϥϜ30.ͱ͸

  17. ήʔϜϓϩάϥϜ͕֨ೲ͞Εͨ30. $16͸ϓϩάϥϜ30.͔Β໋ྩϑΣονͯ͠ϓϩάϥϜ Λ࣮ߦ͢Δ void main() { char i; *(char*)0x2000 =

    0x00; *(char*)0x2001 = 0x00; ͜Μͳͷ͕ "'''"ʜ ͜Μͳײ͡Ͱ٧·ͬͯΔ ϓϩάϥϜ30.ͱ͸
  18. ΩϟϥΫλʔ30.ͱ͸

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

  20. ՄࢹԽͯ͠ΈΔͱ

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

  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.ͷσʔλ
  23. ΤϛϡϨʔλͰ͸͜ΕΒͷ৘ใΛ Ͳ͏औΓѻ͑͹͍͍͔

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

  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.ͷϒϩοΫαΠζ͕ ֨ೲ͞Ε͍ͯΔ
  26. ·ͣ͸ OFTΛಡΜͰղੳͯ͠ ֤30.Λ੾Γग़ͯ͠΍Δඞཁ͕͋Δ

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

  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 ͔Βݺ΂ΔΑ͏ʹ ͜Ε͸Ҿ਺
  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ʹม׵
  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σʔλͷઌ಄ ʢ͢ͳΘͪϙΠϯλʣͱͯ͠αΠζͱҰॹʹڭ͑ ͯ΍Δ
  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. ͷ಺༰Λ࣮ߦ͢Ε͹ήʔϜ͕։࢝͢Δʣ
  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.Λ੾Γग़͢
  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͢Δؔ਺Λ ࢦఆͯ͠΍Δඞཁ͕͋Δ
  34. ϝϞϦʢ3".30.ʣ

  35. pub struct Ram { pub field: Vec<u8>, } impl Ram

    { pub fn new(buf: Vec<u8>) -> 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".ͷ࣮૷
  36. $16͕ϝϞϦʹͲͷΑ͏ʹ ΞΫηε͢Δ͔஌ͬͯ·͔͢ʁ ׂ Ѫ

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

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

    νοϓηϨΫτɺΞυϨεɺϦʔυ৴߸ͳͲ Ϧʔυʹඞཁͳ৴߸͕ଗ͏ͱ3".͔Βσʔλ ׂ Ѫ
  39. ΞυϨε νοϓηϨΫτ Ϧʔυ σʔλ Y%&"% Y#& 43".ͷY%&"%൪஍ʹϦʔυΞΫηεΛߦ͍Y#&͕ಡΈग़͞ΕΔྫ 43".ͷϦʔυλΠϛϯάྫ ͜ͷλΠϛϯάͰY#&Λϥον͢Δ σʔλ͸Ϧʔυ৴߸ͷ্ཱ͕ͪΓ΍ͦͷޙͷ

    $16ΫϩοΫͷ্ཱ͕ͪΓͰऔΓࠐ·ΕΔ΋ͷ͕ଟ͍ σόΠεʹϓϦϯτ͞Ε͍ͯΔ਺ࣈ͸͍͍ͩͨ͜͜ͷ਺ࣈ ʢDZDMF खݩͷ30.͸ͳͷͰ DZDMFOTҎ্ʹͯ͠Ͷͱ͍͏ҙຯ ׂ Ѫ
  40. ͢ͳΘͪɺ͜ΕΒͷ৴߸ΛλΠϛϯάΛकΓͭͭ ༩͑ͯ΍Ε͹Χηοτͷ30.͔Βσʔλ͕ಡΊΔ ׂ Ѫ

  41. $16

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

  43. $16ͷϨδελҰཡ ໊শ αΠζ ৄࡉ " CJU ΞΩϡϜϨʔλ 9 CJU ΠϯσοΫεϨδελ

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

  44. εςʔλεϨδελ CJU ໊শ ৄࡉ ಺༰ CJU / ωΨςΟϒ ԋࢉ݁ՌͷCJU͕ͷ࣌ʹηοτ CJU

    7 Φʔόʔϑϩʔ 1ԋࢉ݁Ռ͕ΦʔόʔϑϩʔΛىͨ࣌͜͠ʹηο τ CJU 3 ༧໿ࡁΈ ৗʹηοτ͞Ε͍ͯΔ CJU # ϒϨʔΫϞʔυ #3,ൃੜ࣌ʹηοτɺ*32ൃੜ࣌ʹΫϦΞ CJU % σγϚϧϞʔυ σϑΥϧτɺ#$%Ϟʔυ ະ࣮૷ CJU * *32ېࢭ *32ڐՄɺ*32ېࢭ CJU ; θϩ ԋࢉ݁Ռ͕ͷ࣌ʹηοτ CJU $ ΩϟϦʔ ΩϟϦʔൃੜ࣌ʹηοτ εςʔλεϨδελͷৄࡉ CJU͸ৗʹͰɺCJU͸/&4Ͱ͸ະ࣮૷
 *32͸ׂΓࠐΈɺ#3,͸ιϑτ΢ΤΞׂΓࠐΈ
  45. 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ͷϨδελͷ࣮૷
  46. ΞυϨε αΠζ ༻్ 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.
  47. 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όεͷ࣮૷ ϝϞϦϚοϓΛ൓ө
  48. $16͸Ͳͷ൪஍͔Β ͲͷλΠϛϯάͰىಈ͢Δ͔

  49. ׂΓࠐΈ

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

  51. ͨͱ͑͹ɺϦηοτʢϑΝϛίϯͷ࢛֯ͷϘλϯͰ͢Ͷʣ΋ׂΓࠐΈͷҰछͰ Ϧηοτ͕ൃੜͨ͠৔߹Y'''$ɺY'''%͔ΒCJUͷΞυϨεΛϦʔυ͠ 1$ʢϓϩάϥϜΧ΢ϯλʣʹηοτ͠ɺηοτ͞ΕͨΞυϨε͔Β࣮ߦ͠·͢ ׂΓࠐΈ ԼҐόΠτ ্ҐόΠτ ֓ཁ /.* Y'''" Y'''#

    ϊϯϚεΧϥϒϧׂΓࠐΈͱݴͬͯ$16͸ଆͰϚεΫͰ͖ͳ ׂ͍ΓࠐΈͰ͢ɻ116ͷׂΓࠐΈग़ྗ৴߸͕઀ଓ͞Ε͍ͯ· ͢ 3&4&5 Y'''$ Y'''% ϦηοτϘλϯԡԼ࣌΍ిݯ౤ೖ࣌ʹ͔͔ΔׂΓࠐΈͰ͢ *32ɺ#3, Y'''& Y'''' #3,͸ιϑτ΢ΣΞׂΓࠐΈͰ#3,໋ྩΛ࣮ߦͨ͠ͱ͖ʹൃ ੜ͠·͢ɻ*32͸"16΍Χηοτʹ઀ଓ͞Ε͍ͯ·͢ ͷ৔߹ҎԼͷΑ͏ͳׂΓࠐΈཁҼ͕༻ҙ͞Ε͍ͯ·͢ ͷׂΓࠐΈ
  52. ϦηοτׂΓࠐΈͷ৔߹

  53. pub fn reset<T: CpuRegisters, U: CpuBus>(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$ʢϓϩάϥϜΧ΢ϯλʣʹηοτ ࣍αΠΫϧ͸ηοτͨ͠ΞυϨε͔Β࣮ߦ͞ΕΔ
  54. /.*ͷ৔߹

  55. pub fn process_nmi<T: CpuRegisters, U: CpuBus>(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)
  56. pub fn process_nmi<T: CpuRegisters, U: CpuBus>(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)
  57. pub fn process_nmi<T: CpuRegisters, U: CpuBus>(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$ʹηοτ
  58. ྫ͑͹/.*લͷ1$͕YɺεςʔλεϨδελ͕Y"" ελοΫϙΠϯλ͕Y''ͩͱ͢Δͱ/.*ޙͷελοΫ͸ҎԼͷΠϝʔδ Y'' Y'&' Y'&& Y'&% Y'& ελοΫϙΠϯλ ʜ Y

    Y Y"" 1$ͷ্ҐΞυϨε 1$ͷԼҐΞυϨε εςʔλεϨδελ ࣍ճͷ164)͸͜͜ʹੵ·ΕΔ /.*ͷ࣮ߦޙͷελοΫΠϝʔδ
  59. ͷ໋ྩ

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

  61. ͨͱ͑͹

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

  63. ུশ ໊લ ֓ཁ 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ͰಘΒΕΔ൪஍ʹ֨ೲ͞Ε͍ͯΔ஋ΛԼҐΞυϨεɺͦͷ࣍ͷ൪஍ʹ֨ೲ͞ Ε͍ͯΔ஋Λ্ҐΞυϨεͱͨ͠൪஍Λԋࢉର৅ͱ͢Δ ΞυϨογϯάϞʔυ
  64. ໋ྩද

  65. ଟ͍

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

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

  68. Yʹͱ͍͏໋ྩ͕֨ೲ͞Ε͍ͯΔ৔߹ ϝϞϦͱ࣮ߦखॱҎԼͷΑ͏ʹͳΔʢ1$΋Yͱ͢Δʣ -%" ʢY"ʣ Y Y" Y ʜ Y -%""

    $16͸1$ ͢ͳΘͪY ͔Β໋ྩΛϑΣον͠1$Λ  ϑΣον݁ՌY"͔Β-%"JNNͰ͋Δͱ൑ผ͞ΕΔ $16͸Y͔ΒΦϖϥϯυY"ΛϑΣον͠1$Λ  Ϩδελ"ʹY"Λ֨ೲ͠ɺ࣍ͷ໋ྩ΁ -%"JNN ࣍ͷ໋ྩ ͜ͷ஋Λ"Ϩδελ ʹϩʔυ͢Δ 1$
  69. pub fn lda_imm<T: CpuRegisters>(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 "ϨδελʹΦϖϥϯυ ʹηοτ ηοτ͞Εͨ஋ʹରԠ͢Δ εςʔλεϑϥάΛηοτ
  70. -%"[QH ্ҐΛYԼҐΛΦϖϥϯυͱͨ͠ΞυϨεʹ ֨ೲ͞Ε͍ͯΔ஋Λ"Ϩδελʹϩʔυ͢Δ

  71. 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$
  72. pub fn lda<T: CpuRegisters, U: CpuBus>(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ԼҐΛΦϖϥϯυͱͨ͠ΞυϨεʹ ֨ೲ͞Ε͍ͯΔ஋Λ"Ϩδελʹϩʔυ͢Δϩʔυ͢Δ Φϖϥϯυͷ஋ΞυϨεͱͯ͠Ϧʔυ Ϧʔυ͞Εͨ஋Λ"Ϩδελʹηοτ
  73. ͜͜·Ͱͷ$16ͷಈ࡞Λ·ͱΊΔͱ

  74. Ϧηοτ ແ͠ ແ͠ ༗Γ ༗Γ ׂΓࠐΈ ༗ແ Φϖϥϯυ ༗ແ Ϩδελͷ

    ঢ়ଶΛୀආ 1$͔Β໋ྩ ΛϑΣον 1$ 1$͔ΒΦϖϥϯυΛ ϑΣον 1$ ໋ྩΛ࣮ߦ ׂΓࠐΈϕΫλ ͷ஋Λ1$ ʹηοτ $16ͷಈ࡞Πϝʔδ Y'''$'''%ʹ ֨ೲ͞Εͨ൪஍͔Β։࢝
  75. pub fn run<T: CpuRegisters + Debug, U: CpuBus>( 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ͷ࣮૷ ׂΓࠐΈͷνΣοΫ
  76. pub fn run<T: CpuRegisters + Debug, U: CpuBus>( 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$͔Β໋ྩΛϑΣον σίʔυ ࣙॻ͔Β໋ྩͷछผɾΞυϨογϯά ϞʔυɺαΠΫϧ਺ͳͲΛҾ͍ͯ͘Δ
  77. $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] }); // …লུ… ΞυϨογϯάϞʔυ΍αΠΫϧ਺ Λ൑ผ
  78. pub fn run<T: CpuRegisters + Debug, U: CpuBus>( 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໋ྩ
  79. ͋ͱ͸໋֤ͭͭ͜͜ྩΛ࣮૷$

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

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

  82. OFTUFTUOFT

  83. 116

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

  85. 116ͷϝϞϦϚοϓ

  86. ΞυϨε αΠζ ֓ཁ 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.
  87. Α͘Θ͔Βͳ͍ςʔϒϧ ͕͍ͬͺ͍

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

  89. ωʔϜςʔϒϧ

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

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

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

  93. ଐੑςʔϒϧ

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

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

     ͜ͷϒϩοΫ Y ͸ ͳͷͰ͕ ࢖༻Ͱ͖Δ ύϨοτ  ͜ͷϒϩοΫ͸ ͜ͷϒϩοΫ͸ ͜ͷϒϩοΫ͸ ଐੑςʔϒϧͱ͸
  96. ύϨοτςʔϒϧ

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

  98. ͨͱ͑͹εύʔϚϦΦϒϥβʔεͷΦʔϓχϯάը໘͸ҎԼͷΑ͏ͳ ύϨοτ͕ઃఆ͞Ε͍ͯΔ ύϨοτY' ύϨοτY' ύϨοτY' ύϨοτY'$ ύϨοτY' ύϨοτY' ύϨοτY' ύϨοτY'$

    എܠ༻ύϨοτʢഎܠ৭৭ ৭YύϨοτͰ৭ʣ εϓϥΠτ༻ύϨοτʢ৭͸ಁ໌৭ͳͷͰ৭YύϨοτͰ৭ʣ ֤ςʔϒϧͷઌ಄ ͸ಁ໌৭ͱͯ͠ ѻΘΕΔ ಁ໌৭ ಁ໌৭ ಁ໌৭ ֤ςʔϒϧͷઌ಄ ͸എܠ৭ എܠ৭ എܠ৭ എܠ৭ ϚϦΦ͸ӈଆͷ৭Ͱදݱ͞Ε͍ͯΔ ύϨοτςʔϒϧͱ͸
  99. ஋ͱ৭ͱͷରԠ͸ʁ

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

    ً౓ ৭౓
  101. 116ͷϨδελΛோΊΔ

  102. ΞυϨε ֓ཁ Y Y CJU આ໌  7#MBOL࣌ʹׂΓࠐΈΛग़ྗ  ৗʹ̍

     εϓϥΠταΠζYY  എܠ༻ύλʔϯςʔϒϧΞυϨεYY  εϓϥΠτύλʔϯςʔϒϧΞυϨεYY  116ΞυϨεΠϯΫϦϝϯτ    ωʔϜςʔϒϧࢦఆ CJU આ໌  എܠ৭CࠇC྘C੨C੺
  εϓϥΠτΠωʔϒϧσΟηʔϒϧΠωʔϒϧ  എܠΠωʔϒϧσΟηʔϒϧΠωʔϒϧ  εϓϥΠτͷը໘ࠨϐΫηϧඳըඳը͠ͳ͍ඳը͢Δ  എܠͷը໘ࠨϐΫηϧඳըඳը͠ͳ͍ඳը͢Δ  σΟεϓϨΠλΠϓΧϥʔϞϊΫϩ 116ͷϨδελ 8SJUF
  103. ΞυϨε ֓ཁ Y εϓϥΠτϝϞϦΞυϨε YΛܦ༝ͯ͠εϓϥΠτϝϞϦ΁ॻ͖ࠐΉϏοτΞυϨεΛࢦఆ Y εϓϥΠτϝϞϦσʔλ YʹΑͬͯࢦఆ͞ΕͨεϓϥΠτϝϞϦΞυϨε΁σʔλΛॻ͖ࠐΉɻ ॻ͖ࠐΉ౓ʹεϓϥΠτϝϞϦΞυϨε͸ΠϯΫϦϝϯτ 

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

    116ϝϞϦσʔλ YʹΑͬͯࢦఆ͞Εͨ116ϝϞϦΞυϨεͷσʔλΛϦʔυ͢Δ Ϧʔυ͢Δ౓ʹϝϞϦΞυϨε͸ΠϯΫϦϝϯτ YͷϏοτʹΑͬͯ ɺ  ͢Δɻ CJU આ໌  7CMBOL࣌ʹ  εϓϥΠτώοτ࣌ʹ  εΩϟϯϥΠϯεϓϥΠτ਺ɹݸҎԼݸҎ্  3FTFSWFE 116ͷϨδελ 3FBE
  105. ͔͜͜Βॏཁͳ΋ͷΛൈ͖ग़ͯ͠ ౎౓આ໌͍͖ͯ͠·͢

  106. தͰ΋ॏཁͳͷ͸

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

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

    $16όε 116όε 116"%%3116%"5"Ϩδελ
  109. Ͳ͏΍ͬͯ࢖͏͔

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

    Ͱࢦఆͨ͠116ϝϞϦۭؒΛಡΈॻ͖͢Δ͜ͱ͕Ͱ͖Δ ʢಡΈॻ͖Λ͢Δͱ116"%%3͸ࣗಈతʹ ·ͨ͸ ΠϯΫϦϝϯτ͞ΕΔʣ 116"%%3116%"5"Ϩδελ
  111. ͜͜·Ͱͷ࿩͔͠Β͢Δͱ 73".ͷ಺༰Λى఺ʹ Ճ޻͍͚ͯ͠͹ ϐΫηϧσʔλΛੜ੒Ͱ͖ͦ͏

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

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

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

                                                                Y ֘౰ͷ࠲ඪ͸ଐੑςʔϒϧͷΞυϨεY%"ʹ֘౰͢ΔͨΊ 73".ͷ͔ΒΞτϦϏϡʔτ͕Ϧʔυ͞ΕΔ Y%"൪஍ Y 116ඳըखॱΠϝʔδ ͜ΜͳεϓϥΠτ σʔλ͕ಘΒΕΔ
  115.  Ϧʔυ͞ΕͨΞτϦϏϡʔτ͔Β֘౰ϙδγϣϯͷύϨοτ൪߸Λ औΓग़͢ͱʹͳΔͷͰύϨοτ͕ద༻͞ΕΔ͜ͱ͕Θ͔Δ  ύϨοτ͢ͳΘͪ73".ͷ#ZUFಡΉͱ ͕ϦʔυͰ͖Δɻ͜ΕΛΧϥʔίʔυදʹద༻͢Δͱ࣍ͷ৭Ͱ͋Δ͜ͱ͕Θ͔Δ ͨΊ3(#ʹม׵֤͠ϐΫηϧʹύϨοτΛద༻ͯ͠΍Δͱ׬੒   

                                ύϨοτ̌ ׬੒✨ C Y'd Y' Y Y Y 116ඳըखॱΠϝʔδ )FMMP 8PSMEͷ)ΛωʔϜςʔϒϧ͔ΒϐΫηϧσʔλʹͯ͠ΈΔྫ
  116. impl Tile { pub fn new<P: PaletteRam>( 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ඳըखॱΠϝʔδ ࠲ඪ͔ΒϒϩοΫ൪߸ Λࢉग़ ࠲ඪͱωʔϜςʔϒϧ͔Β εϓϥΠτ൪߸Λࢉग़
  117. impl Tile { pub fn new<P: PaletteRam>( 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ඳըखॱΠϝʔδ ࠲ඪͱଐੑςʔϒϧ͔Β ΞτϦϏϡʔτΛࢉग़ ΞτϦϏϡʔτͱϒϩοΫ൪߸͔Β ύϨοτ൪߸Λࢉग़
  118. impl Tile { pub fn new<P: PaletteRam>( 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ͷϐΫηϧσʔλΛ ࡞੒
  119. 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(#"ͷϐΫηϧσʔλ ʹม׵
  120. ϐΫηϧσʔλ͸ಘΒΕ͕ͨ Ͳ͏΍ͬͯϒϥ΢βʹදࣔ͢Δ͔

  121. $BOWBT

  122. 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ଆʹެ։Ͱ͖Δ
  123. 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ʹηοτ
  124. 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 ଆͷॲཧ ͜Μͳ;͏ʹݺ΂Δ όοϑΝͷϙΠϯλͱ௕͞Λ ڭ͑ͯ͋͛Δ
  125. ͜ΕͰ73".ͷ಺༰Λ $BOWBTʹॻ͖ग़ͤͦ͏

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

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

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

    ׂ Ѫ
  129. 116ͷඳըλΠϛϯά

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

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

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

  133. MJOFQJYFM EJTQMBZ ࣍ͷඳըͷͨΊʹઌ಄΁໭Δ ͜ͷͨΊͷظؒΛͱݴ͍ MJOF෼ͷ࣌ؒΛཁ͢Δ Ұը໘ͷߋ৽ʹ͸ Y αΠΫϧ ඞཁͱͳΔ ͢ͳΘͪ

    7CMBOL ը໘ͷӈԼ୺ʹ౸ୡ MJOF෼ ͨ͠Βը໘෼ͷඳը͕׬ྃ 116ඳըλΠϛϯά
  134. MJOFQJYFM ͜ͷαΠΫϧΛඵؒʹճ '14 ܁Γฦ͢͜ͱͰ Ωϟϥ΍എܠ͕ͳΊΒ͔ʹಈ͖ήʔϜͱͯ͠੒ཱ͢Δ EJTQMBZ MJOF 116ඳըλΠϛϯά

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

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

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

  138. 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׬͔ྃͨ͠Λ൑ఆ
  139. 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
  140. 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
  141. 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
  142. ͋ͱ͸$16ͱ116ɺඳըͷಉظΛ ͲͷΑ͏ʹͱΔ͔

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

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

    $16ͱ116ͷಉظ
  145. ࣌ؒ NT NT ը໘෼ͷσʔλ͕ Ͱ͖Δ·Ͱ $16116Λ࣮ߦ ը໘෼ͷσʔλ͕ Ͱ͖Δ·Ͱ $16116Λ࣮ߦ ը໘෼ͷσʔλ͕

    Ͱ͖Δ·Ͱ $16116Λ࣮ߦ ඳը ඳը ඳը ͜ΜͳΠϝʔδͰ࣮ߦ͍ͨ͠ NT $16ͱ116ͷಉظ
  146. SFRVFTU"OJNBUJPO'SBNFΛ࢖͍͍ͨ '14Ͱಈ࡞͢ΔΑ͏ʹ͍͍ײ͡ʹ͕Μ͹ͬͯ͘ΕΔ΍ͭ

  147. void emscripten_set_main_loop( em_callback_func func, int fps, int simulate_infinite_loop) FNTDSJQUFOΛ࢖༻͍ͯ͠Δ৔߹͍͕ͭ͜࢖͑Δ ୈೋҾ਺ʹΛηοτ͢ΔͱΛ

    ࢖ͬͯ͘ΕΔ SFRVFTU"OJNBUJPO'SBNF FNTDSJQUFO@TFU@NBJO@MPPQ ୈࡾҾ਺Ληοτ͢ΔͱແݶϧʔϓΛ γϛϡϨʔτ
  148. 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Λ࣮ߦ
  149. 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Λ࣮ߦ
  150. 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; } } } ϝΠϯϧʔϓͷ࣮૷ Ұը໘෼४උ͕Ͱ͖ͨΒϨϯμϦϯά
  151. ͜͜·Ͱ͕࣮૷Ͱ͖Ε͹ )FMMP 8PSME͕ඳըͰ͖ͦ͏

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

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

  154. )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; }
  155. 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
  156. *(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
  157. *(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
  158. )FMMP 8PSME

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

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

  161. εΫϩʔϧ

  162. 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ͷϝϞϦϚοϓ ࠶
  163. ը໘෼ͷςʔϒϧ͸ҎԼͷΑ͏ͳ഑ஔʹͳ͍ͬͯΔ ωʔϜଐੑςʔϒϧ YdY'' ωʔϜଐੑςʔϒϧ YdY'' ωʔϜଐੑςʔϒϧ YdY#'' ωʔϜଐੑςʔϒϧ Y$dY''' 116ͷωʔϜଐੑςʔϒϧͷ഑ஔ

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

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

    εΫϩʔϧͱදࣔྖҬͷؔ܎
  166. εΫϩʔϧؔ͢ΔϨδελ͸ͭ ׂ Ѫ

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

    ͔͠͠ɺ͜ͷϨδελ͚ͩͰ͸QYҎ্ͷεΫϩʔϧ͸ෆՄ ׂ Ѫ
  168. 116$53-Ϩδελ ΞυϨε ֓ཁ Y CJU આ໌ ʜ ʜলུʜ  ωʔϜςʔϒϧࢦఆ

    116$53-Ϩδελ Y ͷCJU͸ωʔϜςʔϒϧΛࢦఆ͢Δ͜ͱ͕Ͱ͖Δ ωʔϜ ଐੑςʔϒϧ ωʔϜ ଐੑςʔϒϧ ωʔϜ ଐੑςʔϒϧ ωʔϜ ଐੑςʔϒϧ ྫ͑͹ωʔϜςʔϒϧࢦఆ͕CͰ͋Ε͹͜ͷςʔϒϧ͕ࢦఆ͞Εͨ͜ͱʹͳΓ Yํ޲ʹQY෼εΫϩʔϧ͕Φϑηοτͨ͜͠ͱͱಉ౳ͱͳΔ ઌͷ1164$30--ͱ߹ΘͤΕ͹ QYҎ্ͷεΫϩʔϧ͕Մೳ ׂ Ѫ
  169. ͜ΕΒΛ࢖͏ͱ໘ന͍දݱ͕Մೳʹ

  170. ϥελεΫϩʔϧ

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

  172. εϓϥΠτ

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

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

  175. 116͸εϓϥΠτ༻ͷྖҬεϓϥΠτ3".Λ͍࣋ͬͯΔ 116ͷϝϞϦϚοϓʹ͸දݱ͞Ε͍ͯͳ͍͓ͦ͠Β͘116಺෦ͷྖҬʁ ΞυϨε ֓ཁ Y εϓϥΠτϝϞϦΞυϨε YΛܦ༝ͯ͠εϓϥΠτϝϞϦ΁ϦʔυϥΠτ͢ΔϏοτΞυϨεΛࢦఆ Y εϓϥΠτϝϞϦσʔλ YʹΑͬͯࢦఆ͞ΕͨεϓϥΠτϝϞϦΞυϨεʹ͍ͨͯ͠ϦʔυϥΠτΛߦ͏

    ΞΫηε͢Δͨͼʹ౓ʹεϓϥΠτϝϞϦΞυϨε͸ΠϯΫϦϝϯτ  ͞ΕΔɻ ΞΫηεํ๏͸116"%%3116%"5" YY ͱ΄΅ಉ͡ ҟͳΔ఺͸εϓϥΠτ3".ͷۭؒ͸CJUͰදݱͰ͖ΔͷͰ ΞυϨεΛઃఆ͢ΔͨΊʹ̎ճॻ͖ࠐΉඞཁ͸ͳ͍ #ZUF εϓϥΠτ3".
  176. εϓϥΠτͭʹରͯ͠ҎԼͷ#ZUFͷઃఆΛ͍࣋ͬͯΔ #ZUF ֓ཁ  :࠲ඪ  εϓϥΠτΠϯσοΫε ΩϟϥΫλʔ30.಺ͷεϓϥΠτͷԿ൪໨ͷεϓϥΠτΛద༻͢Δ͔Λࢦఆ͢Δ  

    9࠲ඪ CJU આ໌  ਨ௚ํ޲൓స൓స͠ͳ͍൓స͢Δ  ਫฏํ޲൓స൓స͠ͳ͍൓స͢Δ  දࣔ༏ઌॱҐεϓϥΠτΛ༏ઌഎܠΛ༏ઌ  ༧໿  ύϨοτ൪߸CύϨοτCύϨοτ CύϨοτCύϨοτ εϓϥΠτ3".͸#ZUFͳͷͰηοτͰ͖Δ ࠷େεϓϥΠτ εϓϥΠτ3".
  177. εϓϥΠτʹؔ͢ΔϢχʔΫͳ࢓༷

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

  179. ΞυϨε ֓ཁ Y CJU આ໌  7CMBOL࣌ʹ  εϓϥΠτώοτ࣌ʹ 

    εΩϟϯϥΠϯεϓϥΠτ਺ɹݸҎԼݸҎ্  3FTFSWFE εϓϥΠτ̌ώοτ εϓϥΠτ3".ͷઌ಄ʹઃఆ͞ΕͨεϓϥΠτ͕ ϥΠϯόοϑΝʹల։͞ΕΔͱ116Ϩδελ Y  ͷʮεϓϥΠτ̌ώοτʯϑϥάཱ͕ͭVOΛ࣮ߦ
  180. ༻్͸ʁ

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

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

  183. εϓϥΠτͷ੍໿

  184. ࣮͸εϓϥΠτ͸ಉҰϥΠϯ্ʹͭ·Ͱ͔͠഑ஔͰ͖ͳ͍ 116͸ϥΠϯόοϑΝΛ͓࣋ͬͯΓ ϥΠϯຖʹεϓϥΠτͱഎܠͷ߹੒Λߦ͍ඳը͍ͯ͠Δ ͜ͷॲཧ͸ίετ͕ߴ͘࠷େͭ·Ͱ͔͠߹੒Ͱ͖ͳ͍Β͍͠ ౰࣌ͷϝϞϦͱίετͷؔ܎͔Β ϑϨʔϜόοϑΝʹ͸Ͱ͖ͳ͔ͬͨΜͩͱਪଌ ΞυϨε ֓ཁ Y CJU

    આ໌ ʜ ʜ  εΩϟϯϥΠϯεϓϥΠτ਺ɹݸҎԼݸҎ্ ʜ ʜ ͜Ε͸্ه੍໿Λݕग़͢ΔͨΊͷػߏ ͕ͩɺόάͬͯΔͱͷӟ΋͋Γ Ͳͷఔ౓࢖༻͞Ε͍ͯͨͷ͔͸ෆ໌ εϓϥΠτͷ੍໿
  185. ൃੜ͢Δ໰୊ͱରࡦʢະݕূʣ

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

    ଜਓ ਓύʔςΟ ൃੜ͢Δ໰୊ͱରࡦʢະݕূʣ
  187. Ͱ΋ɺ͓Ε͸Ͱ͔͍ͬϘεΈͨ͜ͱ͕͋Δͧʂ ͱ͍͏ํ΋͍Δ͔΋

  188. IUUQTXXXZPVUVCFDPNXBUDI W1(1EP1T3ΑΓ εϓϥΠτͰ͸ͳ͘ എܠͰඳը ͜Ε͸εϓϥΠτͰ͸ͳ͘എܠͰϘεΛදݱͯ͠ΔͬΆ͍ εϓϥΠτͰ͋Ε͹ෳࡶͳഎܠͷ্ʹ ߹੒ʢॏͳΓ͕දݱʣ͞Εͯදࣔ͞ΕΔ͕ എܠͰఢΛදݱͯ͠͠·͏ͱॏͶΔ͜ͱ͕Ͱ͖ͳ͍ ͳͷͰɺഎܠ͸ਅͬࠇʹͯ͠ΔͱࢥΘΕΔ ௨ৗഎܠͱͯ͠ඳը͢ΔͰ͋Ζ͏

    ଍৔ΛεϓϥΠτͱͯ͠ඳը ͔ͭӈ͔Βࠨ΁Ҡಈͤ͞Δ͜ͱ ʹΑΓυϥΰϯ͕௥ͬͯ͘ΔΑ͏ʹ දݱ υϥΰϯͷ্ԼҠಈ͸ എܠεΫϩʔϧͰ࣮ݱ ͜͏͍͏΍ͭ
  189. εϓϥΠτͷసૹύϑΥʔϚϯε

  190. ͨͱ͑͹εϓϥΠτ3".#ZUFΛద౰ͳ஋ͰຒΊΔ ؆୯ͳॲཧΛߟ͑ͯΈΔ ldy $FF # 2cycle copysprites: sty $2004 #

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

  192. ղܾࡦ͸ʜ

  193. %." %JSFDUNFNPSZBDDFTT

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

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

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

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

    %." /&4ͷ%."͸͔ͳΓ௿ػೳ
  198. ίϯτϩʔϥ

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

     "  #  4&-&$5  45"35  ্  Լ  ࠨ  ӈ ίϯτϩʔϥ ̎1͸Y
  200. ϒϥ΢βͰͷΤϛϡϨʔγϣϯ

  201. 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෼֬ อͦ͜͠ʹঢ়ଶΛॻ͖ࠐΉ
  202. 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ʜͷॱʹ ஋Λฦ͢Α͏ʹ͓ͯ͘͠
  203. "16 α΢ϯυ ׂ Ѫ

  204. ϑΝϛίϯͷ৔߹"16 ΦʔσΟΦϓϩηογϯάϢχο τʣͱ%"$ σΟδλϧΞφϩάίϯόʔλ ͕$16ʹ ૊Έࠐ·Ε͍ͯΔ "16 α΢ϯυ νϟωϧ͸ۣܗ೾͕νϟωϧɺࡾ֯೾νϟωϧɺϊ Πζνϟωɺ%1$.νϟωϧͷνϟωϧ͕࢖༻Ͱ

    ͖ήʔϜͷԻ͸͜ͷνϟωϧͷ૊Έ߹ΘͤʹΑΓදݱ͞ ΕΔ ׂ Ѫ
  205. IUUQTDPEFQFOJPHSFHIQFOYR8XR[ Πϝʔδ͸͜ͷDPEFQFO͕Θ͔Γ΍͍͢ "16 α΢ϯυ ׂ Ѫ

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

  207. ΞυϨε 38 ༻్ Y 8 ۣܗ೾$)੍ޚϨδελ Y 8 ۣܗ೾$)੍ޚϨδελ Y

    8 ۣܗ೾$)प೾਺Ϩδελ Y 8 ۣܗ೾$)प೾਺Ϩδελ Y 8 ۣܗ೾$)੍ޚϨδελ Y 8 ۣܗ೾$)੍ޚϨδελ Y 8 ۣܗ೾$)प೾਺Ϩδελ Y 8 ۣܗ೾$)प೾਺Ϩδελ Y 8 ࡾ֯೾੍ޚϨδελ Y" 8 ࡾ֯೾प೾਺Ϩδελ Y# 8 ࡾ֯೾प೾਺Ϩδελ "16ͷϨδελҰཡ ׂ Ѫ
  208. ΞυϨε 38 ༻్ Y$ 8 ϊΠζ੍ޚϨδελ Y& 8 ϊΠζཚ਺Ϩδελ Y'

    8 ϊΠζ࣌ؒϨδελ Y 8 %1$.੍ޚϨδελ Y 8 %1$.੍ޚϨδελ Y 8 %1$.੍ޚϨδελ Y 8 %1$.੍ޚϨδελ Y 38 Ի੠νϟωϧ੍ޚϨδελ Y 38 ϑϨʔϜΧ΢ϯλ "16ͷϨδελҰཡ ׂ Ѫ
  209. ۣܗ೾ΛΈ͍ͯ͘ ׂ Ѫ

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

  211. ΞυϨε ֓ཁ Y CJU આ໌  σϡʔςΟൺCC CC  ࠶ੜ࣌ؒΧ΢ϯλΠωʔϒϧ

     ΤϯϕϩʔϓσΟηʔϒϧ  ϘϦϡʔϜ·ͨ͸ΤϯϕϩʔϓσΟόΠμ σϡʔςΟൺ ݮਰͷ଎౓ͳͲΛ੍ޚ ۣܗ೾Ϩδελ ׂ Ѫ
  212. ΞυϨε ֓ཁ Y CJU આ໌  εΠʔϓΠωʔϒϧ  प೾਺มԽ଎౓ 

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

     ΩʔΦϑΧ΢ϯλ  ύϧελΠϚʔ্ҐCJU प೾਺ͱ࠶ੜ࣌ؒΛ੍ޚ ۣܗ೾Ϩδελ ׂ Ѫ
  214. Ͳ͏΍ͬͯΤϛϡϨʔτ͢Δ͔ ׂ Ѫ

  215. 8FC"VEJP ׂ Ѫ

  216. 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Ͱ ΧελϜ೾ܗΛ࡞੒Ͱ͖Δ ׂ Ѫ
  217. 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ଆ΁ެ։ ׂ Ѫ
  218. ͋ͱ͸)[)[ͷपظͱ $16͔ΒͷΞΫηελΠϛϯά प೾਺΍ϘϦϡʔϜͷมಈ͕ൃੜ͢Δ ͷͰͦͷλΠϛϯάͰݺΜͰ΍Ε͹͍͍ ׂ Ѫ

  219. 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 ଆͷॲཧ ׂ Ѫ
  220. ͜͜·ͰͰϑΝϛίϯຊମͷ ϋʔυ΢ΣΞ͸Ұ௨Γ࣮૷Ͱ͖ͨ͸ͣ

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

  222. "͠ͳ͍

  223. ..$ NFNPSZNBOBHFNFOUDPOUSPMMFS

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

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

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

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

  228. .BQQFS

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

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

  231. $)3 30. $/ )$  "" "" %% 8& )$ͰσʔλΛϥον͠

    ΞυϨεʹม׵ ΩϟϥΫλʔ30. όΠφϦΧ΢ϯλ .BQQFSͷճ࿏
  232. 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.΁ͷΞυϨε Λܭࢉͯ͠ฦ͢
  233. ରԠ30.Λ૿΍͢ʹ͸ ֤ͭͭ͜͜.BQQFSͷରԠ͕ඞཁ

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

  235. ύϑΥʔϚϯε

  236. DISPNF  8FC"TTFNCMZWT+BWB4DSJQU DISPNFDBOBSZ  pSFGPY  CJU pSFGPYEFWFMPQFSFEJUJPO C

    CJU TBGBSJ    NT NT NT NT NT NT NT NT NT NT    UJNF<NT> TNBMMFSJTCFUUFS 8FC"TTFNCMZ CPLVXFCSVTUZOFT +BWB4DSJQU CPLVXFCqPXOFT 8FC"VEJP$BOWBTΛσΟηʔϒϧʹͨ͠ঢ়ଶͰ ϝΠϯϧʔϓͷॲཧ࣌ؒճͷฏۉ஋Λൺֱ .BD#PPL"JS JODI &BSMZ ()[*OUFM$PSFJ(#.)[%%3 HJLPOFT
  237. ͍͞͝ʹ !ϑΝϛίϯΤϛϡϨʔλ͸ҰਓͰ࣮૷͢Δͷʹ΋खࠒͳαΠζ !$16΍%."ɺׂΓࠐΈͳͲͷಈ࡞Λֶ΂Δ !ઌਓͷۤ࿑ͷยྡྷΛຯΘ͑Δ !ࣗ෼΋99ݴޠͰ΍ͬͯΈΔ͔ʂͱࢥͬͯ΋Β͑ͨΒخ͍͠Ͱ͢

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