From 36405871d2f92fb34548adc7db097e8a21cddecb Mon Sep 17 00:00:00 2001 From: James Braid Date: Fri, 30 Oct 2026 08:03:24 +0000 Subject: [PATCH 01/11] cpu: keep every implemented VPN2 bit on the R10000 family EntryHi, the TLB match and the xuseg bounds check all stopped at VA bit 39, but the R10000 family implements 44 bits: VPN2 is 43:13 and the user segment is 16 TiB (R10000 UM pp. 219, 288). A 64-bit kernel can put an n64 user stack above 40 bits (0x0fff_ffff_aee4, for one). EntryHi dropped VA[43:40] and such an address took an Address Error. The width now comes from the part's VA_BITS in each place: the EntryHi write mask, the TLB's 64-bit compare (Tlb::set_va_bits, installed by the executor beside set_cache_attrs), the xuseg bounds check, the micro-TLB's cacheable segment test and the EntryHi value a TLB exception loads. The mask was spelled three times and is now one const fn, mips_tlb::vpn2_mask. All of it is a const of the CPU model or set once at construction; the TLB lookup is unchanged. This reverses a comment in the executor (b7d2a18b) that said widening the EntryHi mask breaks the IP28 and Octane kernels. Those two machines and an O2 set to the R10000 now see 44 bits. The R4400 and R5000 (Indy, Indigo2, O2 with an R5000) stay at 40. One test maps a page at 0x123_4000_0000 on the R10000 and the R4400: the R10000 keeps EntryHi and reads the page, the R4400 masks it and takes Address Error. --- CHANGELOG.md | 7 ++++++ src/cpu/mips_core.rs | 14 ++++++----- src/cpu/mips_exec.rs | 52 ++++++++++++++++++++++----------------- src/cpu/mips_exec_test.rs | 50 +++++++++++++++++++++++++++++++++++++ src/cpu/mips_tlb.rs | 17 +++++++++++-- 5 files changed, 110 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de9797b3d..bec8d5701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -171,6 +171,13 @@ hashes are given where a change is easiest to understand by reading the commit. the cost follows what the guest wrote. Reflinking is unchanged. On Windows the copy is marked sparse first. +### R10000 TLB widths + +- **Full 44-bit user addresses.** On the R10000 (Octane, IP28, and an O2 set to + `r10000`) EntryHi, the TLB match and the user-segment check keep VA bits 43:40; + they stopped at bit 39 before, so an address above 1 TiB took an Address Error. + The R4400 and R5000 are unchanged. + ### `IRIS_GUI_GL` works in iris-gui - The GUI's GL capture path (`IRIS_GUI_GL=1`, or `[debug] gui_gl_capture`) never diff --git a/src/cpu/mips_core.rs b/src/cpu/mips_core.rs index 068f7dab0..c786f1835 100644 --- a/src/cpu/mips_core.rs +++ b/src/cpu/mips_core.rs @@ -881,6 +881,7 @@ pub struct MipsCore { pub cp0_errorepc: u64, // 30: Error Exception PC pub tlb_entries: u32, // Total TLB entries + pub entryhi_mask: u64, // Writable EntryHi bits: region, ASID and the model's VPN2 width /// CP0 PRId / CP1 FIR reset values, supplied by the CPU model at construction. pub reset_prid: u32, pub reset_fir: u32, @@ -1413,6 +1414,7 @@ impl MipsCore { cp0_taghi: 0, cp0_errorepc: 0, tlb_entries: 48, + entryhi_mask: 0xC000_00FF_FFFF_E0FF, reset_prid: 0x0000_0440, reset_fir: 0x0000_0500, cp0_random_cycle: 0, @@ -2035,16 +2037,16 @@ impl MipsCore { } 10 => { // always use 64bit mask because the entries need to be valid in 64 bit mode even when they were set from 32 bit mode // `log mips mask cp0` shows what the guest wrote against - // what survives the mask. The mask is R4400's 40-bit virtual - // address; the R10000 implements 44. - if cp0_log() && (value & !0xC000_00FF_FFFF_E0FF) != 0 { + // what survives the mask: the model's VPN2 width, 40 bits or the + // R10000 family's 44. + if cp0_log() && (value & !self.entryhi_mask) != 0 { crate::dlog!(crate::devlog::LogModule::Mips, "ip28ehi: wrote {value:#018x} -> kept {:#018x} (lost {:#018x}) pc={:#018x}", - value & 0xC000_00FF_FFFF_E0FF, - value & !0xC000_00FF_FFFF_E0FF, + value & self.entryhi_mask, + value & !self.entryhi_mask, self.pc); } - self.cp0_entryhi = value & 0xC000_00FF_FFFF_E0FF; + self.cp0_entryhi = value & self.entryhi_mask; }, 11 => { // Materialize the count *first* so both new_delta below and diff --git a/src/cpu/mips_exec.rs b/src/cpu/mips_exec.rs index 782f106b0..063505d9e 100644 --- a/src/cpu/mips_exec.rs +++ b/src/cpu/mips_exec.rs @@ -577,17 +577,23 @@ pub const TR_GLOBAL: u32 = 1 << 4; /// the privilege epoch that filled it. The only thing rejected here is a VA /// shape that is not a valid address in the first place. #[inline] -fn nutlb_cacheable_segment(va: u64, is_64bit: bool) -> bool { +fn nutlb_cacheable_segment(va: u64, is_64bit: bool) -> bool { if !is_64bit { // Every 32-bit segment (kuseg/kseg0/kseg1/ksseg/kseg3) is a real // address whose finished translation is worth caching. return true; } - // xuseg: bits 63:40 must be zero to be a valid user address. Every other - // 64-bit segment (xsseg, xkphys, xkseg and the 0xFFFFFFFF_* compat - // windows) is fine — translate_64bit_impl raises before returning ok for - // the illegal xkphys sub-ranges, so nothing invalid reaches a fill. - (va >> 62) != 0 || (va >> 40) == 0 + // xuseg: bits 63:`C::VA_BITS` must be zero to be a valid user address. + // Every other 64-bit segment (xsseg, xkphys, xkseg and the 0xFFFFFFFF_* + // compat windows) is fine — translate_64bit_impl raises before returning ok + // for the illegal xkphys sub-ranges, so nothing invalid reaches a fill. + (va >> 62) != 0 || (va >> C::VA_BITS) == 0 +} + +/// The EntryHi bits this model keeps: region, VPN2 up to `C::VA_BITS` and ASID. +#[inline(always)] +const fn model_entryhi_mask() -> u64 { + 0xC000_0000_0000_00FF | crate::cpu::mips_tlb::vpn2_mask(C::VA_BITS) } /// Per-access-class tally of how far a guest load/store would get through the @@ -2211,7 +2217,9 @@ impl MipsExecutor { let mut core = MipsCore::new(); // Mapped pages decode their C field with this model's table, as KSEG0 // and xkphys do. + tlb.set_va_bits(C::VA_BITS); tlb.set_cache_attrs(Self::cache_attr_table()); + core.entryhi_mask = model_entryhi_mask::(); // Cache geometry comes from the model type C, so Config describes this CPU. // `mut` is only used by the Triton L2-enable sync below. @@ -2882,7 +2890,7 @@ impl MipsExecutor { // user address. Everything else is cacheable regardless of which // mode filled it, because privilege is enforced by flushing on // transition rather than by the tag. - if !nutlb_cacheable_segment(va, self.core.is_64bit_mode()) { + if !nutlb_cacheable_segment::(va, self.core.is_64bit_mode()) { return; } @@ -4539,11 +4547,11 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", let top_bits = virt_addr >> 62; match top_bits { - // xuseg: 0x0000_0000_0000_0000 - 0x0000_00FF_FFFF_FFFF (user mapped) - // Accessible from all privilege levels + // xuseg is user-mapped below 2^C::VA_BITS (0x0000_00FF_FFFF_FFFF + // for the 40-bit models) and accessible from every privilege level. 0 => { - if (virt_addr >> 40) != 0 { - // Bits 63:40 must be zero for valid user address + if (virt_addr >> C::VA_BITS) != 0 { + // Bits above the model's implemented user VA must be zero if !DEBUG { self.core.cp0_badvaddr = virt_addr; } return TranslateResult::exc(exec_exception(if access_type == AccessType::Write { EXC_ADES } else { EXC_ADEL })); } @@ -4694,8 +4702,12 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", #[inline] fn update_tlb_exception_registers(&mut self, virt_addr: u64) { const EH_VPN2_32: u64 = 0x0000_0000_FFFF_E000; - const EH_VPN2_64: u64 = 0x0000_00FF_FFFF_E000; const EH_REGION: u64 = 0xC000_0000_0000_0000; + // VPN2 is bits 43:13 on the R10000 family (R10000 UM pp. 219, 288) and + // 39:13 on the R4x00 and R5000. The R12000 is inferred to match (its + // manual lists no TLB change); the R14000 and R16000 are a model choice + // that follows the same width. + let eh_vpn2_64 = crate::cpu::mips_tlb::vpn2_mask(C::VA_BITS); self.core.cp0_badvaddr = virt_addr; @@ -4718,9 +4730,9 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", // // This is MAME r4000's `EH_WM` (0xC000_00FF_FFFF_E0FF) less the ASID // bits, which are carried separately below. - const EH_VPN_MASK: u64 = EH_REGION | EH_VPN2_64; // 0xC000_00FF_FFFF_E000 + let eh_vpn_mask = EH_REGION | eh_vpn2_64; let asid = self.core.cp0_entryhi & 0xFF; - self.core.cp0_entryhi = (virt_addr & EH_VPN_MASK) | asid; + self.core.cp0_entryhi = (virt_addr & eh_vpn_mask) | asid; // Context: PTEBase[63:23] preserved, BadVPN2 = virt_addr[31:13] in bits [22:4]. // Always 32-bit VPN — Context is used by the 32-bit UTLB handler. @@ -4741,10 +4753,6 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", // the address it computes lands outside the page table it wired, the // nested miss is unrecoverable, and IRIX panics with "Entered tlbmiss // with invalid vaddr". - // - // EntryHi keeps the 40-bit VPN2 field on every model: a 64-bit kernel - // zero-fills those upper bits itself when it builds an EntryHi value, - // and widening the mask here breaks it. self.core.cp0_xcontext = xcontext_on_miss(C::VA_BITS, self.core.cp0_xcontext, virt_addr); } @@ -7150,12 +7158,12 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", let g1 = (self.core.cp0_entrylo1 & 1) != 0; let g_combined = if g0 && g1 { 1u64 << 12 } else { 0 }; - // EH_WM = 0xC000_00FF_FFFF_E0FF — same mask MAME applies on TLBWI (clears reserved bits). - // Then clear bit 12 (G bit from EntryHi) and set combined G from Lo0&Lo1. - const EH_WM: u64 = 0xC000_00FF_FFFF_E0FF; + // EntryHi's writable mask (0xC000_00FF_FFFF_E0FF on a 40-bit model, MAME's + // `EH_WM`) clears reserved bits, as on TLBWI. Then clear bit 12 (G bit + // from EntryHi) and set combined G from Lo0&Lo1. TlbEntry { page_mask: self.core.cp0_pagemask, - entry_hi: (self.core.cp0_entryhi & EH_WM & !0x1000) | g_combined, + entry_hi: (self.core.cp0_entryhi & self.core.entryhi_mask & !0x1000) | g_combined, entry_lo: [self.core.cp0_entrylo0, self.core.cp0_entrylo1], selector_bit_shift: 0, // all derived fields overwritten by MipsTlb::write() vcmp32: 0, vpn_hi32: 0, vcmp64: 0, vpn_hi64: 0, diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index 4098813ec..45e787b9e 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -6418,4 +6418,54 @@ mod tests { } assert_eq!(outcome[0], outcome[1], "an explanation must not change what the guest sees"); } + + /// Run `f` on a thread with room for a `MipsTlb`, which is large. + fn on_big_stack(f: impl FnOnce() + Send + 'static) { + std::thread::Builder::new().stack_size(16 * 1024 * 1024).spawn(f).unwrap().join().unwrap(); + } + + /// A 64-bit kernel executor with one TLB entry, written through CP0 and + /// TLBWI, that maps the page at `va` to `phys` (cached, valid, dirty). + fn map_page>>( + bus: Arc, va: u64, phys: u64, + ) -> Box> { + let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); + let mut exec = Box::new(MipsExecutor::new(bus, crate::cpu::mips_tlb::MipsTlb::default(), &cfg)); + disable_jitv2(&mut exec); + // MTC0 must refresh the boxed executor's translation/accessor state. + exec.install_status_cb(); + let status = (exec.core.cp0_status & !crate::cpu::mips_core::STATUS_ERL) | STATUS_KX; + let entrylo = ((phys >> 12) << 6) | (3 << 3) | (1 << 2) | (1 << 1); + for (rd, value) in [(12, status as u64), (10, va), (0, 0), (5, 0), (2, entrylo), (3, 0)] { + exec.core.write_gpr(1, value); + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_DMTC0 << 21) | (1 << 16) | (rd << 11)), EXEC_COMPLETE); + } + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | FUNCT_TLBWI), EXEC_COMPLETE); + exec + } + + /// EntryHi and the TLB keep every implemented VPN2 bit: 44 virtual-address + /// bits on the R10000, 40 on the R4400. An IRIX n64 stack can sit + /// above the 40-bit limit. + #[test] + fn cp0_entryhi_and_tlb_match_full_xuseg_va() { + on_big_stack(|| { + const VA: u64 = 0x0000_0123_4000_0000; + fn check>>(full_va: bool) { + let mem = Arc::new(MockMemory::new()); + mem.set_word(0x5_0000, 0xdead_beef); + let mut exec = map_page::(mem, VA, 0x5_0000); + let result = exec.read_data::<4>(VA); + if full_va { + assert_eq!(exec.core.cp0_entryhi, VA); + assert_eq!(result, Ok(0xdead_beef)); + } else { + assert_eq!(exec.core.cp0_entryhi, VA & 0xC000_00FF_FFFF_E0FF); + assert_eq!((result.unwrap_err() >> 2) & 0x1f, EXC_ADEL); + } + } + check::(false); + check::(true); + }); + } } diff --git a/src/cpu/mips_tlb.rs b/src/cpu/mips_tlb.rs index 05680e0c6..275f513e0 100644 --- a/src/cpu/mips_tlb.rs +++ b/src/cpu/mips_tlb.rs @@ -295,6 +295,11 @@ pub enum TlbResult { }, } +/// VPN2 bits of a virtual address `bits` wide: bit 13 up to `bits - 1`. +pub const fn vpn2_mask(bits: u32) -> u64 { + ((1u64 << bits) - 1) & !0x1fff +} + /// TLB interface for MIPS address translation /// /// The TLB translates virtual page numbers to physical page numbers. @@ -351,6 +356,8 @@ pub trait Tlb { fn power_on(&mut self) {} /// Install the CPU model's meaning for each EntryLo C value. fn set_cache_attrs(&mut self, _table: [CacheAttr; 8]) {} + /// Set the implemented VPN width before installing entries. + fn set_va_bits(&mut self, _bits: u32) {} fn save_state(&self) -> toml::Value { toml::Value::Table(Default::default()) } fn load_state(&mut self, _v: &toml::Value) -> Result<(), String> { Ok(()) } @@ -534,6 +541,7 @@ pub struct MipsTlb { /// Live JTLB entries for the CPU model in use (<= TLB_MAX_ENTRIES). num_entries: usize, + vpn_mask64: u64, /// What each EntryLo C value means on the CPU model in use; the /// executor installs its table with `set_cache_attrs`. c_attr: [CacheAttr; 8], @@ -564,6 +572,7 @@ impl MipsTlb { mru_head: [0u8; MRU_LISTS], mru_next: [[MRU_NONE; TLB_MAX_ENTRIES]; MRU_LISTS], num_entries, + vpn_mask64: 0xC000_00FF_FFFF_E000, c_attr: DEFAULT_C_ATTR, vmap: [VMAP_MISS; VMAP_SIZE], #[cfg(feature = "tlbcheck")] @@ -1065,7 +1074,7 @@ impl Tlb for MipsTlb { entry.selector_bit_shift = (mask.trailing_ones() - 1) as u8; entry.vcmp32 = !mask & 0x0000_0000_FFFF_E000; entry.vpn_hi32 = entry.entry_hi & entry.vcmp32; - entry.vcmp64 = !mask & 0xC000_00FF_FFFF_E000; + entry.vcmp64 = !mask & self.vpn_mask64; entry.vpn_hi64 = entry.entry_hi & entry.vcmp64; entry.offset_mask = (1u64 << entry.selector_bit_shift) - 1; let pfn_mask = 0xFF_FFFF_FFFF_000 & !entry.offset_mask; @@ -1194,6 +1203,10 @@ impl Tlb for MipsTlb { output } + fn set_va_bits(&mut self, bits: u32) { + self.vpn_mask64 = 0xC000_0000_0000_0000 | vpn2_mask(bits); + } + fn set_cache_attrs(&mut self, table: [CacheAttr; 8]) { self.c_attr = table; for i in 0..self.num_entries { @@ -1237,7 +1250,7 @@ impl Tlb for MipsTlb { let entry_hi = words[1]; let mask = page_mask | 0x1FFF; let vcmp32 = !mask & 0x0000_0000_FFFF_E000; - let vcmp64 = !mask & 0xC000_00FF_FFFF_E000; + let vcmp64 = !mask & self.vpn_mask64; let shift = (mask.trailing_ones() - 1) as u8; let offset_mask = (1u64 << shift) - 1; let lo = [words[2], words[3]]; From 3a7421741c7b314ab00ae2ac34eeff761be038ad Mon Sep 17 00:00:00 2001 From: James Braid Date: Fri, 30 Oct 2026 05:16:09 -0700 Subject: [PATCH 02/11] cpu: apply FrameMask to EntryLo on a TLB write on the R10000 family FrameMask (CP0 register 21) is new with the R10000. Bits 15:0 clear EntryLo bits 33:18 as a TLB write passes them on, and the rest of the register reads as zero (R10000 UM v2.0 p. 260). iris had no register 21: mfc0 read zero and mtc0 was dropped, so a kernel that sets FrameMask to keep software flags out of the physical address got no effect. The core holds the register; the executor sets which bits are writable, all 16 on the R10000 and none on the R4400 and R5000. TLBWI and TLBWR pass the masked EntryLo values, and TLBR returns the masked entry. The register is saved with the rest of CP0 and loads as zero from an older save. CpuModel::R10K_FAMILY says a part is in the R10000 family; for now that is the R10000. Nothing changes while FrameMask is zero, its reset value, and the write path runs only on a TLB write. Tests write FrameMask on the R10000 and the R4400, map a page and check the physical address and the readback; a second writes with TLBWR as well as TLBWI and reads the entry back with TLBR. --- CHANGELOG.md | 4 +++ src/cpu/mips_cache_shadow.rs | 1 + src/cpu/mips_cache_v2.rs | 7 ++++ src/cpu/mips_core.rs | 19 ++++++++++ src/cpu/mips_exec.rs | 12 +++++-- src/cpu/mips_exec_test.rs | 68 ++++++++++++++++++++++++++++++++++-- 6 files changed, 106 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bec8d5701..a16b5cfc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -177,6 +177,10 @@ hashes are given where a change is easiest to understand by reading the commit. `r10000`) EntryHi, the TLB match and the user-segment check keep VA bits 43:40; they stopped at bit 39 before, so an address above 1 TiB took an Address Error. The R4400 and R5000 are unchanged. +- **FrameMask (CP0 register 21)** on the R10000 clears the EntryLo bits it + names, 33:18, on every TLB write, so a kernel that keeps software flags there + gets the physical address it meant. The register read as zero and ignored + writes before. The R4400 and R5000 have none. ### `IRIS_GUI_GL` works in iris-gui diff --git a/src/cpu/mips_cache_shadow.rs b/src/cpu/mips_cache_shadow.rs index 53b6673eb..73ab609ba 100644 --- a/src/cpu/mips_cache_shadow.rs +++ b/src/cpu/mips_cache_shadow.rs @@ -347,6 +347,7 @@ impl< _ => "shadow", }; const CACHE_KIND: &'static str = "shadow"; + const R10K_FAMILY: bool = Self::R10K_CACHE_OPS; const R10K_CACHE_OPS: bool = MODEL == model::R10000; } diff --git a/src/cpu/mips_cache_v2.rs b/src/cpu/mips_cache_v2.rs index 3dffd558c..8b6b49e15 100644 --- a/src/cpu/mips_cache_v2.rs +++ b/src/cpu/mips_cache_v2.rs @@ -565,6 +565,12 @@ pub trait CpuModel: MipsCache { /// and `Index_Load_Data` returns into it, neither of which is true of the /// R4000 hit operations that share those encodings. const R10K_CACHE_OPS: bool = false; + /// The part is in the R10000 family, which shares one programming model: + /// FrameMask, and 44 virtual and 40 physical address bits. + /// Established for the R10000. The R12000 is inferred to match: its manual's + /// list of changes from the R10000 has no TLB or CP0 change. The R14000 and + /// R16000 are a model choice that gives them the same TLB. + const R10K_FAMILY: bool = false; } pub trait MipsCache: Send + Sync { @@ -3595,6 +3601,7 @@ impl self.cp0_watchlo as u64, 19 => self.cp0_watchhi as u64, 20 => self.cp0_xcontext, + 21 => self.cp0_framemask as u64, 25 => { // PerfCnt: R4400 has no performance counters. Log any probe so // a guest expecting them (and routing their overflow onto the @@ -1690,6 +1696,7 @@ impl MipsCore { 18 => self.cp0_watchlo as u64, 19 => self.cp0_watchhi as u64, 20 => self.cp0_xcontext, + 21 => self.cp0_framemask as u64, 26 => self.cp0_ecc as u64, 27 => self.cp0_cacheerr as u64, 28 => self.cp0_taglo, @@ -1699,6 +1706,14 @@ impl MipsCore { } } + /// An EntryLo value as a TLB write passes it on: FrameMask bits 15:0 clear + /// EntryLo bits 33:18, so the flags IRIX keeps above the PFN's low bits + /// never reach the physical address (R10000 UM v2.0 p. 260). + #[inline] + pub fn framemask_entrylo(&self, lo: u64) -> u64 { + lo & !((self.cp0_framemask as u64) << 18) + } + /// Materialize the virtual CP0 Count: advance `cp0_count` by the whole /// hardware ticks elapsed since the anchor at `count_hz`, move the anchor /// forward by exactly the duration those ticks consumed (the sub-tick @@ -2255,6 +2270,10 @@ impl MipsCore { } self.cp0_xcontext = value; } + // FrameMask: bits 15:0 are implemented, the rest read as zero + // (R10000 UM v2.0 p. 260). Other parts have no register 21 and ignore + // the write. + 21 => self.cp0_framemask = value as u32 & self.framemask_mask, 25 => { #[cfg(feature = "developer_ip7")] eprintln!("[ip7] MTC0 PerfCnt (reg 25) write {:#018x} (ignored)", value); diff --git a/src/cpu/mips_exec.rs b/src/cpu/mips_exec.rs index 063505d9e..346eeab12 100644 --- a/src/cpu/mips_exec.rs +++ b/src/cpu/mips_exec.rs @@ -2220,6 +2220,9 @@ impl MipsExecutor { tlb.set_va_bits(C::VA_BITS); tlb.set_cache_attrs(Self::cache_attr_table()); core.entryhi_mask = model_entryhi_mask::(); + if C::R10K_FAMILY { + core.framemask_mask = 0xFFFF; + } // Cache geometry comes from the model type C, so Config describes this CPU. // `mut` is only used by the Triton L2-enable sync below. @@ -7164,7 +7167,10 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", TlbEntry { page_mask: self.core.cp0_pagemask, entry_hi: (self.core.cp0_entryhi & self.core.entryhi_mask & !0x1000) | g_combined, - entry_lo: [self.core.cp0_entrylo0, self.core.cp0_entrylo1], + entry_lo: [ + self.core.framemask_entrylo(self.core.cp0_entrylo0), + self.core.framemask_entrylo(self.core.cp0_entrylo1), + ], selector_bit_shift: 0, // all derived fields overwritten by MipsTlb::write() vcmp32: 0, vpn_hi32: 0, vcmp64: 0, vpn_hi64: 0, offset_mask: 0, pfn_base: [0; 2], @@ -11049,7 +11055,7 @@ impl Saveable for MipsCpu cp0u64!(cp0_taglo); cp0u32!(cp0_taghi); cp0u64!(cp0_badvaddr); cp0u64!(cp0_epc); cp0u64!(cp0_errorepc); cp0u64!(cp0_entrylo0); cp0u64!(cp0_entrylo1); cp0u64!(cp0_context); - cp0u64!(cp0_pagemask); cp0u64!(cp0_entryhi); cp0u64!(cp0_xcontext); + cp0u64!(cp0_pagemask); cp0u64!(cp0_entryhi); cp0u64!(cp0_xcontext); cp0u32!(cp0_framemask); tbl.insert("cp0".into(), toml::Value::Table(cp0)); // FPU @@ -11114,7 +11120,7 @@ impl Saveable for MipsCpu ld32!(cp0_ecc); ld32!(cp0_cacheerr); ld64!(cp0_taglo); ld32!(cp0_taghi); ld64!(cp0_entrylo0); ld64!(cp0_entrylo1); ld64!(cp0_context); ld64!(cp0_pagemask); ld64!(cp0_badvaddr); ld64!(cp0_entryhi); - ld64!(cp0_xcontext); ld64!(cp0_epc); ld64!(cp0_errorepc); + ld64!(cp0_xcontext); ld32!(cp0_framemask); ld64!(cp0_epc); ld64!(cp0_errorepc); // Restart the virtual count from the restored value and re-arm // the compare timer — Instants from the previous run are // meaningless here — with a live ticket for the restored deadline. diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index 45e787b9e..e8468873a 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -3744,6 +3744,56 @@ mod tests { check::(0xF_FFFF_FFFF); } + /// FrameMask bits 15:0 clear EntryLo bits 33:18 as a TLB write takes them, + /// on the R10000 only (R10000 UM v2.0 p. 260). Physical bit 24 is EntryLo bit 18, + /// mask bit 0; the R4400 has no such register. + #[test] + fn framemask_clears_entrylo_bits_on_a_tlb_write() { + fn phys>>(framemask: u64) -> (u64, u64) { + const VA: u64 = 0x4000_0000; + let mut exec = map_page_masked::(Arc::new(MockMemory::new()), VA, 0x0300_5000, framemask); + (exec.core.read_cp0(21), exec.debug_translate(VA).phys) + } + use crate::cpu::mips_cache_shadow::R10000ShadowCache; + on_big_stack(|| { + // Mask bit 0 is written with bits above 15, which are ignored. + let all = 0xFFFF_0001; + assert_eq!(phys::(0), (0, 0x0300_5000)); + assert_eq!(phys::(all), (1, 0x0200_5000)); + assert_eq!(phys::(all), (0, 0x0300_5000)); + }); + } + + /// TLBWR masks as TLBWI does, and TLBR returns what the TLB holds: the + /// masked EntryLo, not the value that was written. + #[test] + fn framemask_applies_to_tlbwr_and_tlbr_reads_back_the_masked_entry() { + use crate::cpu::mips_cache_shadow::R10000ShadowCache; + // Write with `funct`, find the entry with TLBP, clear EntryLo0, TLBR, + // and return (physical address of the page, EntryLo0 after TLBR). + fn entry>>(funct: u32) -> (u64, u64) { + const VA: u64 = 0x4000_0000; + let mut exec = map_page_with::(Arc::new(MockMemory::new()), VA, 0x0300_5000, 0xFFFF_0001, funct); + let phys = exec.debug_translate(VA).phys; + for (rd, value) in [(10, VA), (2, 0)] { + exec.core.write_gpr(1, value); + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_DMTC0 << 21) | (1 << 16) | (rd << 11)), EXEC_COMPLETE); + } + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | FUNCT_TLBP), EXEC_COMPLETE); + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | FUNCT_TLBR), EXEC_COMPLETE); + (phys, exec.core.read_cp0(2)) + } + on_big_stack(|| { + // FrameMask bit 0 clears EntryLo bit 18, physical bit 24. + let unmasked = ((0x0300_5000u64 >> 12) << 6) | (3 << 3) | (1 << 2) | (1 << 1); + let masked = unmasked & !(1 << 18); + for funct in [FUNCT_TLBWI, FUNCT_TLBWR] { + assert_eq!(entry::(funct), (0x0200_5000, masked), "R10000 {funct:#x}"); + assert_eq!(entry::(funct), (0x0300_5000, unmasked), "R4400 {funct:#x}"); + } + }); + } + /// The Indy, Indigo2 and O2 decode 32 physical bits, and IRIX relies on /// it: on the IP28 the kernel stack's wired entry carries PTE software /// bits as PA[34:33]. `phys_mask` must fold them away before the bus. @@ -6428,6 +6478,20 @@ mod tests { /// TLBWI, that maps the page at `va` to `phys` (cached, valid, dirty). fn map_page>>( bus: Arc, va: u64, phys: u64, + ) -> Box> { + map_page_masked::(bus, va, phys, 0) + } + + /// `map_page` with CP0 FrameMask (register 21) written before the TLB write. + fn map_page_masked>>( + bus: Arc, va: u64, phys: u64, framemask: u64, + ) -> Box> { + map_page_with::(bus, va, phys, framemask, FUNCT_TLBWI) + } + + /// `map_page_masked`, writing the entry with `funct` (TLBWI or TLBWR). + fn map_page_with>>( + bus: Arc, va: u64, phys: u64, framemask: u64, funct: u32, ) -> Box> { let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); let mut exec = Box::new(MipsExecutor::new(bus, crate::cpu::mips_tlb::MipsTlb::default(), &cfg)); @@ -6436,11 +6500,11 @@ mod tests { exec.install_status_cb(); let status = (exec.core.cp0_status & !crate::cpu::mips_core::STATUS_ERL) | STATUS_KX; let entrylo = ((phys >> 12) << 6) | (3 << 3) | (1 << 2) | (1 << 1); - for (rd, value) in [(12, status as u64), (10, va), (0, 0), (5, 0), (2, entrylo), (3, 0)] { + for (rd, value) in [(12, status as u64), (10, va), (0, 0), (5, 0), (21, framemask), (2, entrylo), (3, 0)] { exec.core.write_gpr(1, value); assert_eq!(exec.exec((OP_COP0 << 26) | (RS_DMTC0 << 21) | (1 << 16) | (rd << 11)), EXEC_COMPLETE); } - assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | FUNCT_TLBWI), EXEC_COMPLETE); + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | funct), EXEC_COMPLETE); exec } From f5b84265e3c634db83733454ffdc1c0d7f501799 Mon Sep 17 00:00:00 2001 From: James Braid Date: Fri, 30 Oct 2026 05:16:10 -0700 Subject: [PATCH 03/11] cpu: widen EntryLo to the R10000's 40 physical bits On the R10000 EntryLo holds a 28-bit PFN in bits 33:6, a 40-bit physical address, and the two-bit uncached attribute in bits 63:62; 61:34 are reserved (R10000 UM v2.0 pp. 239-240). iris kept the R4400's 30 bits, so the attribute and PFN bits 33:30 read back as zero and never reached the TLB. The core now has an EntryLo mask that the executor sets per part: the R4400 and R5000 keep 0x3FFF_FFFF, the R10000 gets 0xC000_0003_FFFF_FFFF. The uncached attribute is stored and read back only; it is not carried to the bus. Bits 33:32 are physical 39:38, where the Octane's guest keeps software flags; FrameMask (previous commit) clears them on a TLB write, so the page lands at its real address. A TLB write also clears the PFN bits below the page size, so TLBR does not return what was written to them (R10000 UM v2.0 pp. 299-300). The manual documents this for the R10000 only; the later parts follow it as a model choice. The R4400 and R5000 keep the whole PFN. Translation already ignored those bits, so only TLBR changes. The Octane PROM's tlb diagnostic writes 0xa5a5a5a4 and 0x5a5a5a58 with 16 KB pages and expects 0xa5a5a524 and 0x5a5a5a18 back; it reported 320 compare errors. On the Octane, the IP28 and an O2 set to the R10000, mfc0 of EntryLo now returns bits 63:62 and PFN bits 33:30 if the guest wrote them. The R4400 and R5000 are unchanged. Tests check the readback on the R10000 and the R4400, that a page with PFN bits 33:32 set maps to physical 39:38 and is brought back by FrameMask, and the diagnostic's patterns through TLBWI and TLBWR. --- CHANGELOG.md | 9 ++++ src/cpu/mips_core.rs | 14 +++--- src/cpu/mips_exec.rs | 18 ++++++-- src/cpu/mips_exec_test.rs | 94 +++++++++++++++++++++++++++++++++++++++ src/ip30_machine.rs | 5 ++- 5 files changed, 128 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a16b5cfc0..418ff9310 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -181,6 +181,15 @@ hashes are given where a change is easiest to understand by reading the commit. names, 33:18, on every TLB write, so a kernel that keeps software flags there gets the physical address it meant. The register read as zero and ignored writes before. The R4400 and R5000 have none. +- **EntryLo** on the R10000 keeps its 28-bit PFN (bits 33:6, a 40-bit physical + address) and the uncached attribute in 63:62; it kept 30 bits before. The + attribute is stored and read back, not sent to the bus. +- **TLB writes on the R10000** store zeros in the PFN bits below the page size, + so TLBR reads them back as zero, as the part does; on 16 KB pages that is + EntryLo bits 7:6. Translation is unchanged. The PROM's `ide` `tlb` test + failed 320 compares on this. The manual documents it for the R10000; the + R12000, R14000 and R16000 do the same as a model choice. The R4400 and + R5000 still keep the whole PFN. ### `IRIS_GUI_GL` works in iris-gui diff --git a/src/cpu/mips_core.rs b/src/cpu/mips_core.rs index 1d3c2ac89..1643bf6d4 100644 --- a/src/cpu/mips_core.rs +++ b/src/cpu/mips_core.rs @@ -884,6 +884,7 @@ pub struct MipsCore { pub tlb_entries: u32, // Total TLB entries pub entryhi_mask: u64, // Writable EntryHi bits: region, ASID and the model's VPN2 width + pub entrylo_mask: u64, // Writable EntryLo bits: 29:0, or on the R10000 family the PFN (33:6) and uncached attribute (63:62) /// CP0 PRId / CP1 FIR reset values, supplied by the CPU model at construction. pub reset_prid: u32, pub reset_fir: u32, @@ -1419,6 +1420,7 @@ impl MipsCore { cp0_errorepc: 0, tlb_entries: 48, entryhi_mask: 0xC000_00FF_FFFF_E0FF, + entrylo_mask: 0x3FFF_FFFF, reset_prid: 0x0000_0440, reset_fir: 0x0000_0500, cp0_random_cycle: 0, @@ -1619,8 +1621,8 @@ impl MipsCore { self.update_random(); self.cp0_random as u64 } - 2 => self.cp0_entrylo0 & 0x3FFFFFFF, // PFN is 24 bits (29:6), flags in lower bits - 3 => self.cp0_entrylo1 & 0x3FFFFFFF, // PFN is 24 bits (29:6), flags in lower bits + 2 => self.cp0_entrylo0 & self.entrylo_mask, + 3 => self.cp0_entrylo1 & self.entrylo_mask, 4 => self.cp0_context, 5 => self.cp0_pagemask & 0x01FFE000, // PageMask: only bits 24:13 are valid 6 => self.cp0_wired as u64 & 0x3F, // Wired: only bits 5:0 are valid, R4000 manual Table 4-10 @@ -1678,8 +1680,8 @@ impl MipsCore { match reg { 0 => self.cp0_index as u64, 1 => self.cp0_random as u64, - 2 => self.cp0_entrylo0 & 0x3FFFFFFF, - 3 => self.cp0_entrylo1 & 0x3FFFFFFF, + 2 => self.cp0_entrylo0 & self.entrylo_mask, + 3 => self.cp0_entrylo1 & self.entrylo_mask, 4 => self.cp0_context, 5 => self.cp0_pagemask & 0x01FFE000, 6 => self.cp0_wired as u64 & 0x3F, @@ -2028,8 +2030,8 @@ impl MipsCore { 0 => self.cp0_index = (value as u32) & (crate::cpu::mips_exec::CP0_INDEX_P | crate::cpu::mips_exec::CP0_INDEX_SLOT_MASK), 1 => { /* Random is read-only */ } - 2 => self.cp0_entrylo0 = value & 0x3FFFFFFF, // PFN is 24 bits (29:6), flags in lower bits - 3 => self.cp0_entrylo1 = value & 0x3FFFFFFF, // PFN is 24 bits (29:6), flags in lower bits + 2 => self.cp0_entrylo0 = value & self.entrylo_mask, + 3 => self.cp0_entrylo1 = value & self.entrylo_mask, 4 => { //eprintln!("MTC0 Context = {:#018x} (PTEBase={:#018x})", value, value & 0xFFFFFFFF_FF800000); self.cp0_context = value; diff --git a/src/cpu/mips_exec.rs b/src/cpu/mips_exec.rs index 346eeab12..66490b192 100644 --- a/src/cpu/mips_exec.rs +++ b/src/cpu/mips_exec.rs @@ -590,6 +590,9 @@ fn nutlb_cacheable_segment(va: u64, is_64bit: bool) -> bool { (va >> 62) != 0 || (va >> C::VA_BITS) == 0 } +/// PageMask bit n covers physical address bit n-1, which is EntryLo bit n-7. +const PAGEMASK_TO_ENTRYLO: u32 = 7; + /// The EntryHi bits this model keeps: region, VPN2 up to `C::VA_BITS` and ASID. #[inline(always)] const fn model_entryhi_mask() -> u64 { @@ -2222,6 +2225,9 @@ impl MipsExecutor { core.entryhi_mask = model_entryhi_mask::(); if C::R10K_FAMILY { core.framemask_mask = 0xFFFF; + // PFN in bits 33:6 and the uncached attribute in 63:62 (R10000 UM v2.0 + // pp. 239-240); 61:34 are reserved. + core.entrylo_mask = 0xC000_0003_FFFF_FFFF; } // Cache geometry comes from the model type C, so Config describes this CPU. @@ -7164,13 +7170,17 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", // EntryHi's writable mask (0xC000_00FF_FFFF_E0FF on a 40-bit model, MAME's // `EH_WM`) clears reserved bits, as on TLBWI. Then clear bit 12 (G bit // from EntryHi) and set combined G from Lo0&Lo1. + // + // The R10000 family stores zeros in the PFN bits the page size leaves + // out of the address, so TLBR does not return them (R10000 UM v2.0 + // pp. 299-300). The manual documents this for the R10000 only; the + // later parts follow it as a model choice. + let unused_pfn = if C::R10K_FAMILY { (self.core.cp0_pagemask & 0x01FF_E000) >> PAGEMASK_TO_ENTRYLO } else { 0 }; + let lo = |v: u64| self.core.framemask_entrylo(v) & !unused_pfn; TlbEntry { page_mask: self.core.cp0_pagemask, entry_hi: (self.core.cp0_entryhi & self.core.entryhi_mask & !0x1000) | g_combined, - entry_lo: [ - self.core.framemask_entrylo(self.core.cp0_entrylo0), - self.core.framemask_entrylo(self.core.cp0_entrylo1), - ], + entry_lo: [lo(self.core.cp0_entrylo0), lo(self.core.cp0_entrylo1)], selector_bit_shift: 0, // all derived fields overwritten by MipsTlb::write() vcmp32: 0, vpn_hi32: 0, vcmp64: 0, vpn_hi64: 0, offset_mask: 0, pfn_base: [0; 2], diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index e8468873a..366e3fe8d 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -3794,6 +3794,100 @@ mod tests { }); } + /// The R10000 writes zeros into the PFN bits a page size leaves out of the + /// address, so TLBR returns them as zero (R10000 UM v2.0 pp. 299-300, TLBWI + /// and TLBWR); the later parts do the same as a model choice, since no + /// manual describes their TLB write. The R4400 keeps the whole PFN. The values are the PROM + /// diagnostic's patterns on 16 KB pages, where EntryLo bits 7:6 go unused. + /// Translation is the same on both: those bits never reach the address. + #[test] + fn tlb_write_clears_pfn_bits_below_the_page_size_on_the_r10000() { + use crate::cpu::mips_cache_shadow::R10000ShadowCache; + // Write (lo0, lo1) with PageMask 0x6000 through TLBWI or TLBWR, then + // find the entry with TLBP and TLBR it back. Returns (EntryLo0, EntryLo1, physical address of + // VA + 0x3000). + fn entry>>(funct: u32, lo0: u64, lo1: u64) -> (u64, u64, u64) { + const VA: u64 = 0x4000_0000; + let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); + let mut exec = Box::new(MipsExecutor::::new( + Arc::new(MockMemory::new()) as Arc, crate::cpu::mips_tlb::MipsTlb::default(), &cfg)); + disable_jitv2(&mut exec); + exec.install_status_cb(); + let status = (exec.core.cp0_status & !crate::cpu::mips_core::STATUS_ERL) | STATUS_KX; + let dmtc0 = |rd: u32| (OP_COP0 << 26) | (RS_DMTC0 << 21) | (1 << 16) | (rd << 11); + for (rd, value) in [(12, status as u64), (10, VA), (0, 0), (5, 0x6000), (2, lo0), (3, lo1)] { + exec.core.write_gpr(1, value); + assert_eq!(exec.exec(dmtc0(rd)), EXEC_COMPLETE); + } + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | funct), EXEC_COMPLETE); + let phys = exec.debug_translate(VA + 0x3000).phys; + // TLBWR picked the slot: find it with TLBP. + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | FUNCT_TLBP), EXEC_COMPLETE); + for rd in [2, 3] { + exec.core.write_gpr(1, 0); + assert_eq!(exec.exec(dmtc0(rd)), EXEC_COMPLETE); + } + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | FUNCT_TLBR), EXEC_COMPLETE); + (exec.core.read_cp0(2), exec.core.read_cp0(3), phys) + } + on_big_stack(|| { + for funct in [FUNCT_TLBWI, FUNCT_TLBWR] { + let (lo0, lo1) = (0xFFFF_FFFF_A5A5_A5A4, 0x5A5A_5A58); + // EntryLo 7:6 cleared; 63:62 and 33:6 otherwise kept. + assert_eq!(entry::(funct, lo0, lo1).0, 0xC000_0003_A5A5_A524, "R10000 {funct:#x}"); + assert_eq!(entry::(funct, lo0, lo1).1, 0x5A5A_5A18, "R10000 {funct:#x}"); + assert_eq!(entry::(funct, lo1, lo0).0, 0x5A5A_5A18, "R10000 {funct:#x}"); + // The R4400 keeps bits 29:0 as written. + assert_eq!(entry::(funct, lo0, lo1).0, 0x25A5_A5A4, "R4400 {funct:#x}"); + assert_eq!(entry::(funct, lo0, lo1).1, 0x1A5A_5A58, "R4400 {funct:#x}"); + + // A 16 KB page at 0x0300_4000 written with PFN bits for + // 0x0300_7000: both parts translate from the 16 KB frame. + let lo = ((0x0300_7000u64 >> 12) << 6) | (3 << 3) | (1 << 2) | (1 << 1); + let (r10k, _, r10k_pa) = entry::(funct, lo, 0); + let (r4k, _, r4k_pa) = entry::(funct, lo, 0); + assert_eq!((r10k, r10k_pa), (lo & !0xC0, 0x0300_7000), "R10000 {funct:#x}"); + assert_eq!((r4k, r4k_pa), (lo, 0x0300_7000), "R4400 {funct:#x}"); + } + }); + } + + /// On the R10000 family EntryLo holds a 28-bit PFN (33:6) and the uncached + /// attribute in 63:62 (R10000 UM v2.0 pp. 239-240); the R4400 and R5000 keep a + /// 24-bit PFN and nothing above it. The TLB carries the whole PFN. + #[test] + fn entrylo_covers_the_pfn_and_attribute_bits_of_the_r10000_family() { + fn readback>>() -> u64 { + let bus: Arc = Arc::new(MockMemory::new()); + let mut exec = MipsExecutor::::new(bus, PassthroughTlb::default(), &MipsCpuConfig::indy()); + disable_jitv2(&mut exec); + exec.core.write_gpr(1, u64::MAX); + // DMTC0 $1, EntryLo0 and EntryLo1; both read back the same field. + for reg in [2u32, 3] { + assert_eq!(exec.exec((0x10 << 26) | (5 << 21) | (1 << 16) | (reg << 11)), EXEC_COMPLETE); + } + let (lo0, lo1) = (exec.core.read_cp0(2), exec.core.read_cp0(3)); + assert_eq!(lo0, lo1); + lo0 + } + assert_eq!(readback::(), 0x3FFF_FFFF); + // Bits 61:34 are not PFN: they read back as zero, so only 33:32 reach physical 39:38. + assert_eq!(readback::(), 0xC000_0003_FFFF_FFFF); + + // The TLB carries the whole PFN: bits 33:32 are physical 39:38, and FrameMask + // is what keeps software flags there out of the address. + on_big_stack(|| { + const VA: u64 = 0x4000_0000; + let mut exec = map_page::( + Arc::new(MockMemory::new()), VA, 0xC0_2054_C000); + assert_eq!(exec.debug_translate(VA).phys, 0xC0_2054_C000); + // FrameMask 0xC000 is EntryLo 33:32: the page lands where its PFN says. + let mut exec = map_page_masked::( + Arc::new(MockMemory::new()), VA, 0xC0_2054_C000, 0xC000); + assert_eq!(exec.debug_translate(VA).phys, 0x2054_C000); + }); + } + /// The Indy, Indigo2 and O2 decode 32 physical bits, and IRIX relies on /// it: on the IP28 the kernel stack's wired entry carries PTE software /// bits as PA[34:33]. `phys_mask` must fold them away before the bus. diff --git a/src/ip30_machine.rs b/src/ip30_machine.rs index f2b2cc15e..63b5e589d 100644 --- a/src/ip30_machine.rs +++ b/src/ip30_machine.rs @@ -599,8 +599,9 @@ impl OctaneMachine { // IRIX zeroes Count and arms Compare a few instructions later; see // `MipsCore::count_write_samples`. exec.core.count_write_samples = true; - // The R10000 drives 40 physical address bits; HEART decodes them - // all, and the attribute bits above fold away. + // The R10000 drives 40 physical address bits; HEART decodes them all. + // EntryLo bits 33:32 are physical 39:38; a guest that keeps software + // flags there clears them with FrameMask, so no narrowing is needed. exec.phys_mask = (1 << 40) - 1; exec.core.cpu_id = id; exec.core.smp = cpu_count > 1; From b41f7f05ec7f00ed17836b46be538e044a130299 Mon Sep 17 00:00:00 2001 From: James Braid Date: Sun, 1 Nov 2026 19:02:01 -0700 Subject: [PATCH 04/11] cpu: choose the R10000 refill vector by address space The R10000 picks the TLB refill vector from the address space the missing address lies in and that space's Status bit: user addresses follow UX, xsseg SX, and kseg3, sseg/ksseg and xkseg KX. The current mode only decides which space an address is in (R10000 UM v2.0 pp. 333-334, 342). The manual contrasts this with the R4400, which picks by the current mode's bit. iris did the R4400 thing on every model. So a 64-bit kernel (KX=1, UX=0) missing on a kuseg address went to the XTLB vector at 0x080 on the R10000, where the part uses 0x000. The Octane PROM's utlb diagnostic loads VA 0 in exactly that state and waits at the 32-bit vector. It got "Read TLB miss exception" from the XTLB vector instead and failed. On the R10000 family a refill miss now reads the region of the address, sign-extended from 32 bits in 32-bit mode, and tests UX, SX or KX. Only the miss path changes. The TLB compare width still follows the mode. The test misses in each space with each bit on the R10000, and checks the R4400 keeps choosing by mode. --- CHANGELOG.md | 5 ++++ src/cpu/mips_exec.rs | 17 ++++++++++++- src/cpu/mips_exec_test.rs | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 418ff9310..ce5c7d5e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -190,6 +190,11 @@ hashes are given where a change is easiest to understand by reading the commit. failed 320 compares on this. The manual documents it for the R10000; the R12000, R14000 and R16000 do the same as a model choice. The R4400 and R5000 still keep the whole PFN. +- **TLB refill vector on the R10000** follows the address space that missed: + a user address takes the XTLB vector only with UX set, xsseg with SX, and + kernel addresses with KX. A 64-bit kernel touching a 32-bit user address now + refills through 0x000, as the part does, not 0x080. The R4400 and R5000 still + choose by the current mode. ### `IRIS_GUI_GL` works in iris-gui diff --git a/src/cpu/mips_exec.rs b/src/cpu/mips_exec.rs index 66490b192..a9b78fe0c 100644 --- a/src/cpu/mips_exec.rs +++ b/src/cpu/mips_exec.rs @@ -4687,7 +4687,8 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", TlbResult::Miss { .. } => { if !DEBUG { self.update_tlb_exception_registers::(virt_addr); } // Miss: XTLB vector (0x080) for 64-bit extended addresses, UTLB vector (0x000) otherwise - TranslateResult::exc(if XTLB != 0 { exec_xtlb_miss(tlb_miss_code) } else { exec_tlb_miss(tlb_miss_code) }) + let xrefill = if C::R10K_FAMILY { self.r10k_xtlb_refill::(virt_addr) } else { XTLB != 0 }; + TranslateResult::exc(if xrefill { exec_xtlb_miss(tlb_miss_code) } else { exec_tlb_miss(tlb_miss_code) }) } TlbResult::Invalid { .. } => { if !DEBUG { self.update_tlb_exception_registers::(virt_addr); } @@ -4701,6 +4702,20 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", } } + /// Whether a refill miss on `virt_addr` takes the XTLB vector on the + /// R10000 family: it follows the address space (UX for user, SX for + /// xsseg, KX otherwise), not the mode, unlike the R4400 (R10000 UM v2.0 + /// pp. 333-334, 342). A 32-bit mode sign-extends the address first. + #[inline(always)] + fn r10k_xtlb_refill(&self, virt_addr: u64) -> bool { + use crate::cpu::mips_core::{STATUS_KX, STATUS_SX, STATUS_UX}; + const _: () = assert!(STATUS_SX == STATUS_UX << 1 && STATUS_KX == STATUS_SX << 1); + let va = if XTLB != 0 { virt_addr } else { virt_addr as u32 as i32 as i64 as u64 }; + // Region 0 is UX, 1 is SX, 2 and 3 are KX: three adjacent Status bits. + let bit = (va >> 62).min(2) as u32; + (self.core.cp0_status & (STATUS_UX << bit)) != 0 + } + /// Debug helper to translate address without side effects pub fn debug_translate(&mut self, virt_addr: u64) -> TranslateResult { self.translate_impl::(virt_addr, AccessType::Debug) diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index 366e3fe8d..3a40d7eac 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -5832,6 +5832,57 @@ mod tests { assert_ne!(st & EXEC_IS_XTLB_REFILL, 0, "true xkseg is unchanged: XTLB"); } + /// The R10000 picks the refill vector by the address space a missing + /// address lies in and that space's Status bit: user addresses follow + /// UX, xsseg SX, kernel and compat supervisor addresses KX (R10000 UM + /// v2.0 pp. 333-334). The R4400 picks by the current mode. A 64-bit + /// kernel (KX=1, UX=0) missing on kuseg therefore takes the 32-bit refill + /// vector on the R10000 and XTLB on the R4400; the PROM's utlb + /// diagnostic waits at the 32-bit vector for exactly that miss. + #[test] + fn r10000_refill_vector_follows_the_address_space() { + use crate::cpu::mips_cache_shadow::R10000ShadowCache; + use crate::cpu::mips_core::{STATUS_ERL, STATUS_EXL, STATUS_SX, STATUS_UX}; + use crate::cpu::mips_exec::EXEC_IS_XTLB_REFILL; + // Kernel mode with `xbits` set in Status, empty TLB; is a read of + // `va` a refill miss through XTLB? + fn xrefill>>(xbits: u32, va: u64) -> bool { + let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); + let mut exec = Box::new(MipsExecutor::::new( + Arc::new(MockMemory::new()), crate::cpu::mips_tlb::MipsTlb::default(), &cfg)); + disable_jitv2(&mut exec); + exec.install_status_cb(); + let status = (exec.core.cp0_status & !(STATUS_ERL | STATUS_EXL | STATUS_KX | STATUS_SX | STATUS_UX | 0x18)) | xbits; + exec.core.write_gpr(1, status as u64); + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_DMTC0 << 21) | (1 << 16) | (12 << 11)), EXEC_COMPLETE); + let st = exec.read_data::<4>(va).expect_err("empty TLB must miss"); + assert_ne!(st & EXEC_IS_TLB_REFILL, 0, "{va:#x} should be a refill miss"); + st & EXEC_IS_XTLB_REFILL != 0 + } + const KUSEG: u64 = 0; + const XSSEG: u64 = 0x4000_0000_0000_0000; + const CKSSEG: u64 = 0xFFFF_FFFF_C000_0000; + const XKSEG: u64 = 0xC000_0000_0000_0000; + on_big_stack(|| { + type R10k = R10000ShadowCache; + // 64-bit kernel, 32-bit user space: kuseg refills through 0x000. + assert!(!xrefill::(STATUS_KX, KUSEG)); + assert!(xrefill::(STATUS_KX, KUSEG), "R4400 follows the mode"); + assert!(xrefill::(STATUS_KX | STATUS_UX, KUSEG)); + // xsseg follows SX, compat ksseg and xkseg follow KX. + assert!(!xrefill::(STATUS_KX, XSSEG)); + assert!(xrefill::(STATUS_KX | STATUS_SX, XSSEG)); + assert!(xrefill::(STATUS_KX, CKSSEG)); + assert!(xrefill::(STATUS_KX, XKSEG)); + // 32-bit kernel: kseg3-side addresses use 0x000, kuseg follows UX. + assert!(!xrefill::(0, CKSSEG)); + assert!(!xrefill::(STATUS_UX, CKSSEG)); + assert!(!xrefill::(0, KUSEG)); + assert!(xrefill::(STATUS_UX, KUSEG)); + assert!(!xrefill::(STATUS_UX, KUSEG), "R4400 follows the mode"); + }); + } + #[test] fn test_xtlb_compare_width_disambiguates_region_field() { std::thread::Builder::new() From 156483e7815a65cb69e0185c6c20461a31cd7175 Mon Sep 17 00:00:00 2001 From: James Braid Date: Sun, 1 Nov 2026 23:00:04 -0700 Subject: [PATCH 05/11] cpu: invalidate overlapping TLB entries on a write on the R10000 family The R10000 and R12000 do not shut down on a multiple match. A TLB write that would let one lookup match two entries first invalidates every entry it overlaps, the wired ones included, then writes the new entry and sets Status.TS (NEC U10278EJ4V0UM, Status register TS bit p.223 and "Avoiding TLB Conflict" p.300). iris stored the entry and left the duplicates matchable, so which one answered depended on how the lookup map happened to be rebuilt. On the two-processor Tezro the firmware flushes the TLB with 64 invalid entries on the kernel's page number, and the kernel then writes the valid global 16 MiB entry over them; a later write elsewhere left an invalid duplicate answering, and the fetch took TLB Invalid. The R14000 gets the same rule as a model choice; no manual for it was read. The R4400 and R5000 keep their behaviour. An overlap is two entries a lookup could match together: same region and page number under the wider of the two page masks, and equal ASIDs or either entry global. Invalid entries count. The removed entry reads back as an unwritten slot except for its PageMask: the kernel TLBRs its wired sentinel entries and reuses PageMask for the next write, and a zeroed mask made it write a per-CPU mapping as 4 KiB. The cost is confined to TLB writes on these models. An entry that overlaps the new one covers a lookup-map slot the new one covers, so a write whose slots are all empty or its own skips the scan. A PageMask that is not a run of ones, which software can write, defeats the map's ranges and turns the shortcut off. A refill that replaces a one-page entry nothing else covers skips the walk over the other entries. TLBWI and TLBWR are never compiled by jitv2, so both reach the same write and set TS in the interpreter. Tests cover the Tezro sequence, wired entries, PageMask kept on a read-back, entries that cannot match together, and TS from TLBWI and TLBWR. They fail with the rule off, and the R4400 and R5000 test fails if the rule is enabled for them. --- src/cpu/mips_exec.rs | 10 ++ src/cpu/mips_exec_test.rs | 58 ++++++++++++ src/cpu/mips_tlb.rs | 124 ++++++++++++++++++++++++- src/cpu/mips_tlb_test.rs | 189 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 379 insertions(+), 2 deletions(-) diff --git a/src/cpu/mips_exec.rs b/src/cpu/mips_exec.rs index a9b78fe0c..568fc4b65 100644 --- a/src/cpu/mips_exec.rs +++ b/src/cpu/mips_exec.rs @@ -2211,6 +2211,13 @@ impl MipsExecutor { self.sysad.describe_fault(phys_addr, size).map_or_else(String::new, |why| format!(" [{why}]")) } + /// Status.TS follows a TLB write that left two entries matching. Branchless: + /// a refill handler writes often and the flag is almost always clear. + #[inline(always)] + fn note_tlb_write_conflict(&mut self) { + self.core.cp0_status |= crate::cpu::mips_core::STATUS_TS & 0u32.wrapping_sub(self.tlb.take_write_conflict() as u32); + } + /// Create a new executor from a config and a bus (sysad) and a TLB. /// The cache hierarchy is constructed internally as a unified R4000Cache. pub fn new(sysad: Arc, mut tlb: T, cfg: &MipsCpuConfig) -> Self @@ -2222,6 +2229,7 @@ impl MipsExecutor { // and xkphys do. tlb.set_va_bits(C::VA_BITS); tlb.set_cache_attrs(Self::cache_attr_table()); + tlb.set_conflict_invalidation(C::R10K_FAMILY); core.entryhi_mask = model_entryhi_mask::(); if C::R10K_FAMILY { core.framemask_mask = 0xFFFF; @@ -7256,6 +7264,7 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", let entry = self.create_tlb_entry_from_cp0(); self.ip28_trace_tlb_write("tlbwi", index, &entry); self.tlb.write(index, entry); + self.note_tlb_write_conflict(); // Flushes the nutlb too — the TLB it caches just changed. self.nanotlb_invalidate(); @@ -7280,6 +7289,7 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", let entry = self.create_tlb_entry_from_cp0(); self.ip28_trace_tlb_write("tlbwr", index, &entry); self.tlb.write(index, entry); + self.note_tlb_write_conflict(); self.nanotlb_invalidate(); if mips_log(MIPS_LOG_TLB) { dlog_dev!(LogModule::Mips, "TLBWR: Write Random Index {}\n{}", index, self.tlb.format_entry(index)); } diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index 3a40d7eac..afc15cf7b 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -1227,6 +1227,64 @@ mod tests { 0xAAAAAAAA means a stale nanotlb slot survived the switch"); } + /// Two writes that would match together: on the R10000 family the second + /// removes the first and sets Status.TS, for TLBWI and TLBWR alike; on the + /// R4400 and R5000 both entries stay and TS stays clear. The compiled-code + /// path has nothing to add: jitv2 never admits TLBWI or TLBWR into a + /// region (see the `tlb_ops_are_never_admitted_but_eret_is` test), so + /// they always run this interpreter code. + fn overlapping_tlb_writes(r10k: bool) + where C: CpuModel + From> { + use crate::cpu::mips_tlb::{MipsTlb, Tlb}; + use crate::cpu::mips_core::STATUS_TS; + let mem: Arc = Arc::new(MockMemory::new()); + let mut exec = MipsExecutor::::new(mem, MipsTlb::default(), &MipsCpuConfig::indy()); + disable_jitv2(&mut exec); + let tlbwi = (OP_COP0 << 26) | (0x10 << 21) | 0x02; + let tlbwr = (OP_COP0 << 26) | (0x10 << 21) | 0x06; + let write = |exec: &mut MipsExecutor, instr: u32, index: u32, pfn: u64| { + exec.core.cp0_index = index; + exec.core.cp0_pagemask = 0; + exec.core.cp0_entryhi = (0x100 << 13) | 10; + exec.core.cp0_entrylo0 = (pfn << 6) | (3 << 3) | (1 << 2) | (1 << 1); + exec.core.cp0_entrylo1 = ((pfn + 1) << 6) | (3 << 3) | (1 << 2) | (1 << 1); + assert_eq!(exec.exec(instr), EXEC_COMPLETE); + }; + let first_survives = |exec: &MipsExecutor| exec.tlb.read(5).entry_hi == (0x100 << 13) | 10; + + write(&mut exec, tlbwi, 5, 0x50); + assert_eq!(exec.core.cp0_status & STATUS_TS, 0, "a write that overlaps nothing leaves TS clear"); + + write(&mut exec, tlbwi, 6, 0x60); + assert_eq!(exec.core.cp0_status & STATUS_TS != 0, r10k, "TLBWI TS"); + assert_eq!(!first_survives(&exec), r10k, "TLBWI removes the overlapped entry"); + if r10k { + assert_eq!(exec.tlb.read(5).page_mask, 0, "PageMask kept"); + } + + // Software clears TS by writing Status; the next overlap sets it again. + exec.core.cp0_status &= !STATUS_TS; + write(&mut exec, tlbwi, 5, 0x50); + exec.core.cp0_status &= !STATUS_TS; + exec.core.cp0_wired = 7; // Random stays out of 0..7, so it cannot pick entries 5 or 6 + write(&mut exec, tlbwr, 0, 0x70); + assert_eq!(exec.core.cp0_status & STATUS_TS != 0, r10k, "TLBWR TS"); + assert_eq!(!first_survives(&exec), r10k, "TLBWR removes the overlapped entry"); + } + + #[test] + fn overlapping_tlb_writes_follow_the_cpu_family() { + std::thread::Builder::new() + .stack_size(64 * 1024 * 1024) + .spawn(|| { + overlapping_tlb_writes::(true); + overlapping_tlb_writes::(true); + overlapping_tlb_writes::(false); + overlapping_tlb_writes::(false); + }) + .unwrap().join().unwrap(); + } + #[cfg(feature = "tlbcheck")] #[test] fn test_tlbwi_breaks_on_duplicate_entry() { diff --git a/src/cpu/mips_tlb.rs b/src/cpu/mips_tlb.rs index 275f513e0..166e2bc47 100644 --- a/src/cpu/mips_tlb.rs +++ b/src/cpu/mips_tlb.rs @@ -358,6 +358,17 @@ pub trait Tlb { fn set_cache_attrs(&mut self, _table: [CacheAttr; 8]) {} /// Set the implemented VPN width before installing entries. fn set_va_bits(&mut self, _bits: u32) {} + /// Make a TLB write invalidate every other entry it would match together + /// with, as the R10000 and R12000 do (NEC U10278EJ4V0UM, Status register + /// TS bit, p.223, and "Avoiding TLB Conflict", p.300): they do not shut + /// down on a multiple match. The R14000 and R16000 are given the same + /// rule as a model choice, matching QEMU's r10k_invalidate_conflicts(); + /// no manual for them was read. Off for the R4400 and R5000, whose + /// behaviour on a multiple match is not modelled. + fn set_conflict_invalidation(&mut self, _on: bool) {} + /// Whether a write since the last call invalidated another entry. The + /// executor reports it in Status.TS. + fn take_write_conflict(&mut self) -> bool { false } fn save_state(&self) -> toml::Value { toml::Value::Table(Default::default()) } fn load_state(&mut self, _v: &toml::Value) -> Result<(), String> { Ok(()) } @@ -560,9 +571,76 @@ pub struct MipsTlb { vmap_touched: std::collections::HashSet, #[cfg(feature = "tlbstats")] pub stats: TlbStats, + /// R10000 family: a write invalidates the entries it overlaps. See + /// [`Tlb::set_conflict_invalidation`]. + invalidate_on_write: bool, + /// Entries written since power-on; a never-written slot cannot conflict. + written: u64, + /// A write invalidated another entry since `take_write_conflict`. + write_conflict: bool, + /// Some entry written since power-on has a PageMask that is not a run of + /// ones from bit 13 (software can write any of bits 24:13). The map + /// ranges of such an entry are not exact, so `invalidate_overlapped` then + /// scans instead of asking the map. + irregular_mask: bool, } impl MipsTlb { + /// The R10000 family never lets a write create a multiple match: every + /// other entry the incoming one could match together with, wired or not, + /// is invalidated first and Status.TS records it (see + /// [`Tlb::set_conflict_invalidation`]). Write path only. + fn invalidate_overlapped(&mut self, index: usize, new: &TlbEntry) { + // An entry that overlaps the new one covers a lookup-map slot the new + // one covers (the map is keyed on VA[31:13], and agreeing on more bits + // agrees on these), and a slot covered by two entries is tagged + // VMAP_MULTI or names the other one. So when every slot of the new + // entry's range is empty or names only `index` (the entry being + // replaced), nothing overlaps and the scan can be skipped. + if !self.irregular_mask { + let (start, count) = Self::vmap_range(new); + let tag = index as u8; + // A 4 KiB page, the refill case, covers one slot. + let clear = if count == 1 { + let v = self.vmap[start]; + v == VMAP_MISS || v == tag + } else { + self.vmap[start..start + count].iter().all(|&v| v == VMAP_MISS || v == tag) + }; + if clear { + return; + } + } + let mut live = self.written & !(1u64 << index); + while live != 0 { + let i = live.trailing_zeros() as usize; + live &= live - 1; + if i >= self.num_entries { + continue; + } + let other = &self.entries[i]; + if !(new.is_global() || other.is_global() || new.asid() == other.asid()) { + continue; + } + let both = new.page_mask | other.page_mask | 0x1FFF; + if (new.entry_hi ^ other.entry_hi) & !both & self.vpn_mask64 != 0 { + continue; + } + let old_range = Self::vmap_range(other); + // TLBR of the entry reads zeros for EntryHi and EntryLo but still + // loads PageMask: software that sets PageMask once and relies on a + // read-back restoring it would otherwise write its next entry + // with a 4 KiB mask. + let mut gone = TlbEntry::new(); + gone.page_mask = other.page_mask; + self.entries[i] = gone; + self.shadow[i] = ShadowEntry::invalid(); + self.written &= !(1u64 << i); + self.vmap_vacate(i, old_range); + self.write_conflict = true; + } + } + pub fn new(num_entries: usize) -> Self { assert!(num_entries > 1 && num_entries <= TLB_MAX_ENTRIES, "MipsTlb supports 2..={} entries, got {}", TLB_MAX_ENTRIES, num_entries); @@ -579,6 +657,10 @@ impl MipsTlb { vmap_touched: std::collections::HashSet::new(), #[cfg(feature = "tlbstats")] stats: TlbStats::default(), + invalidate_on_write: false, + written: 0, + write_conflict: false, + irregular_mask: false, }; for list in 0..MRU_LISTS { tlb.mru_head[list] = 0; @@ -678,7 +760,26 @@ impl MipsTlb { /// step 3 that it now also aliases. #[inline] fn vmap_replace(&mut self, index: usize, old_range: (usize, usize)) { + self.vmap_vacate(index, old_range); + let (new_start, new_count) = Self::vmap_range(&self.entries[index]); + self.vmap_fill_range(index, new_start, new_count); + } + + /// Steps 1 to 3 of [`Self::vmap_replace`]: take `index` out of the map + /// and let the other entries reclaim what it covered. + #[inline] + fn vmap_vacate(&mut self, index: usize, old_range: (usize, usize)) { let (old_start, old_count) = old_range; + // One slot that only `index` covers (named by it, no VMAP_MULTI): + // no other entry covers it, so none has anything to reclaim and the + // walk below would find nothing. A refill replaces an entry this way. + // Slot 0 is left to the walk: the zeroed entries of a TLB that was + // never written, and the entries an overlapping write cleared, all + // read as covering it. + if old_count == 1 && old_start != 0 && self.vmap[old_start] == index as u8 { + self.vmap_clear(old_start, 1); + return; + } self.vmap_clear(old_start, old_count); let old_end = old_start + old_count; for i in 0..self.num_entries { @@ -694,8 +795,6 @@ impl MipsTlb { self.vmap_fill_range(i, lo, hi - lo); } } - let (new_start, new_count) = Self::vmap_range(&self.entries[index]); - self.vmap_fill_range(index, new_start, new_count); } /// Full internal consistency check (feature = "tlbcheck"). @@ -1082,6 +1181,11 @@ impl Tlb for MipsTlb { (entry.entry_lo[0] << 6) & pfn_mask, (entry.entry_lo[1] << 6) & pfn_mask, ]; + self.irregular_mask |= mask & (mask + 1) != 0; + if self.invalidate_on_write { + self.invalidate_overlapped(index, &entry); + } + self.written |= 1 << index; let old_range = Self::vmap_range(&self.entries[index]); self.entries[index] = entry; self.shadow[index] = ShadowEntry::from_entry(&entry, &self.c_attr); @@ -1203,6 +1307,14 @@ impl Tlb for MipsTlb { output } + fn set_conflict_invalidation(&mut self, on: bool) { + self.invalidate_on_write = on; + } + + fn take_write_conflict(&mut self) -> bool { + std::mem::take(&mut self.write_conflict) + } + fn set_va_bits(&mut self, bits: u32) { self.vpn_mask64 = 0xC000_0000_0000_0000 | vpn2_mask(bits); } @@ -1225,6 +1337,9 @@ impl Tlb for MipsTlb { self.mru_next[list][self.num_entries - 1] = MRU_NONE; } self.vmap.fill(VMAP_MISS); + self.written = 0; + self.write_conflict = false; + self.irregular_mask = false; #[cfg(feature = "tlbcheck")] { self.vmap_touched.clear(); } } @@ -1281,6 +1396,11 @@ impl Tlb for MipsTlb { self.mru_next[list][self.num_entries - 1] = MRU_NONE; } self.vmap.fill(VMAP_MISS); + self.written = !0u64 >> (64 - self.num_entries); + self.irregular_mask = self.entries[..self.num_entries].iter().any(|e| { + let mask = e.page_mask | 0x1FFF; + mask & (mask + 1) != 0 + }); for i in 0..self.num_entries { let (start, count) = Self::vmap_range(&self.entries[i]); self.vmap_fill_range(i, start, count); diff --git a/src/cpu/mips_tlb_test.rs b/src/cpu/mips_tlb_test.rs index 4ebbaeda1..d594d6e74 100644 --- a/src/cpu/mips_tlb_test.rs +++ b/src/cpu/mips_tlb_test.rs @@ -4,6 +4,195 @@ mod tests { use crate::cpu::mips_tlb::*; use crate::cpu::mips_exec::CacheAttr; + /// Region 3 base for the overlap tests below; the frame is arbitrary. + const BASE: u64 = 0xc000_0000_0000_0000; + + fn entry(mask: u64, hi: u64, lo: [u64; 2]) -> TlbEntry { + let mut e = TlbEntry::new(); + e.page_mask = mask; + e.entry_hi = hi; + e.entry_lo = lo; + e + } + + /// CPU 1 of a two-processor Tezro as its TLB looks after the firmware's + /// flush (every entry written invalid: region 3, page number 0, ASID 0, + /// not global, 2 MiB pages) and the kernel's write of the valid global + /// 16 MiB entry at index 1 over the same page number. The firmware + /// entries that overlap it are true duplicates: every compared bit agrees. + fn flushed_then_kernel_mapped(invalidate: bool) -> MipsTlb { + let mut tlb = MipsTlb::new(64); + tlb.set_conflict_invalidation(invalidate); + for index in (0..64).rev() { + tlb.write(index, entry(0x1fe000, BASE, [0; 2])); + } + // PFN 0x40, cacheable, dirty, valid, global, both halves. + tlb.write(1, entry(0x1ffe000, BASE | 0x1000, [(0x40 << 6) | (5 << 3) | 0x7; 2])); + tlb + } + + /// An entry elsewhere, as the kernel writes at index 0 next (wired). + fn write_wired_elsewhere(tlb: &mut MipsTlb) { + tlb.write(0, entry(0x6000, 0xc000_0fff_ffff_9000, [1, 0x2e42f])); + } + + /// Writing the valid entry takes the overlapped firmware entries out of + /// matching, as the R10000 family does, so the fetch the kernel makes + /// next is answered by the valid entry however the lookup map was + /// rebuilt in between. Without the rule the highest-numbered firmware + /// entry answers, as invalid. + #[test] + fn a_write_invalidates_the_entries_it_overlaps() { + std::thread::Builder::new().stack_size(64 << 20).spawn(|| { + let va = BASE + 0x1234; + let mut off = flushed_then_kernel_mapped(false); + write_wired_elsewhere(&mut off); + assert!(matches!(off.translate::<1>(va, 0, AccessType::Fetch), TlbResult::Invalid { .. }), + "without the rule, the duplicate answers"); + assert!(!off.take_write_conflict()); + assert_eq!(off.read(2).entry_hi, BASE, "without the rule, the duplicate stays"); + + let mut tlb = flushed_then_kernel_mapped(true); + assert!(tlb.take_write_conflict(), "the writes overlapped entries"); + write_wired_elsewhere(&mut tlb); + match tlb.translate::<1>(va, 0, AccessType::Fetch) { + TlbResult::Hit { phys_addr, .. } => assert_eq!(phys_addr, 0x1234), + other => panic!("expected the valid entry to answer, got {other:?}"), + } + assert_eq!(tlb.read(2).entry_hi, 0); + assert_eq!(tlb.read(1).page_mask, 0x1ffe000); + // An entry in another region overlaps nothing and removes nothing. + tlb.write(5, entry(0x1fe000, 0x8000_0000_0000_0000, [0; 2])); + assert!(!tlb.take_write_conflict()); + assert!(matches!(tlb.translate::<1>(va, 0, AccessType::Fetch), TlbResult::Hit { .. })); + }).unwrap().join().unwrap(); + } + + /// The rule reaches the wired entries (the low indexes the kernel + /// reserves): a new entry over a wired one removes the wired one. + #[test] + fn a_write_invalidates_wired_entries_too() { + std::thread::Builder::new().stack_size(64 << 20).spawn(|| { + let va = BASE + 0x2345; + let lo = |pfn: u64| [(pfn << 6) | (5 << 3) | 0x7; 2]; + let run = |on: bool| { + let mut tlb = MipsTlb::new(64); + tlb.set_conflict_invalidation(on); + tlb.write(0, entry(0, BASE | 0x2000, lo(0x10))); + tlb.write(40, entry(0, BASE | 0x2000, lo(0x20))); + tlb + }; + let on = run(true); + assert!(on.read(0).entry_hi == 0 && on.read(0).entry_lo == [0; 2], "wired entry 0 is gone"); + assert_eq!(on.read(40).entry_hi, BASE | 0x2000); + let mut on = on; + assert!(on.take_write_conflict()); + match on.translate::<1>(va, 0, AccessType::Read) { + TlbResult::Hit { phys_addr, .. } => assert_eq!(phys_addr, (0x20 << 12) | 0x345), + other => panic!("expected the new entry to answer, got {other:?}"), + } + let off = run(false); + assert_eq!(off.read(0).entry_hi, BASE | 0x2000, "without the rule the wired entry stays"); + }).unwrap().join().unwrap(); + } + + /// TLBR of an invalidated entry still loads its PageMask. The kernel + /// reads a wired sentinel back and reuses PageMask for its next write; a + /// zeroed mask makes that write 4 KiB. + #[test] + fn an_invalidated_entry_keeps_its_page_mask() { + std::thread::Builder::new().stack_size(64 << 20).spawn(|| { + let mut tlb = MipsTlb::new(64); + tlb.set_conflict_invalidation(true); + tlb.write(3, entry(0x1fe000, BASE, [0x7; 2])); + tlb.write(9, entry(0x1ffe000, BASE, [0x7; 2])); + let gone = tlb.read(3); + assert_eq!(gone.page_mask, 0x1fe000); + assert_eq!(gone.entry_hi, 0); + assert_eq!(gone.entry_lo, [0; 2]); + assert_eq!(tlb.read(9).page_mask, 0x1ffe000); + }).unwrap().join().unwrap(); + } + + /// Entries that cannot match together are left alone: a different ASID + /// when neither is global, and a page number that differs above the + /// wider mask. + #[test] + fn entries_that_cannot_match_together_are_kept() { + std::thread::Builder::new().stack_size(64 << 20).spawn(|| { + let mut tlb = MipsTlb::new(64); + tlb.set_conflict_invalidation(true); + tlb.write(3, entry(0, BASE | 0x4000 | 1, [0x6; 2])); // ASID 1, not global + tlb.write(4, entry(0, BASE | 0x4000 | 2, [0x6; 2])); // ASID 2 + tlb.write(5, entry(0, BASE | 0x8000 | 1, [0x6; 2])); // other page + assert!(!tlb.take_write_conflict()); + for i in [3, 4, 5] { + assert_ne!(tlb.read(i).entry_hi, 0, "entry {i} stays"); + } + // A global entry over that page does match both ASIDs. + tlb.write(6, entry(0, BASE | 0x4000 | 0x1000, [0x7; 2])); // global + assert!(tlb.take_write_conflict()); + assert_eq!(tlb.read(3).entry_hi, 0); + assert_eq!(tlb.read(4).entry_hi, 0); + assert_ne!(tlb.read(5).entry_hi, 0); + }).unwrap().join().unwrap(); + } + + /// The overlap rule written out directly: what a write must remove. + fn overlaps(new: &TlbEntry, other: &TlbEntry) -> bool { + if !(new.is_global() || other.is_global() || new.asid() == other.asid()) { + return false; + } + let both = new.page_mask | other.page_mask | 0x1FFF; + (new.entry_hi ^ other.entry_hi) & !both & 0xC000_00FF_FFFF_E000 == 0 + } + + /// Random writes against a plain list that applies the rule by comparing + /// every pair. The lookup map is how a write finds out it overlaps + /// nothing, so the TLB must agree with the list after every write, with + /// regular page masks and with masks that are not a run of ones. + #[test] + fn writes_remove_exactly_the_overlapped_entries() { + std::thread::Builder::new().stack_size(64 << 20).spawn(|| { + for masks in [&[0u64, 0x6000, 0x1e000, 0x7e000, 0x1fe000, 0x7fe000, 0x1ffe000][..], + &[0u64, 0x6000, 0x2000, 0xa000, 0x1fe000, 0x1ffe000][..]] { + let mut rng = 0x9e37_79b9_7f4a_7c15u64; + let mut next = move || { rng ^= rng << 13; rng ^= rng >> 7; rng ^= rng << 17; rng }; + let mut tlb = MipsTlb::new(64); + tlb.set_conflict_invalidation(true); + let mut model: Vec> = vec![None; 64]; + for _ in 0..4000 { + let index = (next() % 64) as usize; + let mask = masks[(next() % masks.len() as u64) as usize]; + let region = if next() % 4 == 0 { 0x8000_0000_0000_0000 } else { BASE }; + // Few page numbers, so that writes collide often. + let page = (next() % 24) << 13; + let asid = next() % 3; + let global = if next() % 3 == 0 { 0x1000 } else { 0 }; + let new = entry(mask, region | page | global | asid, [(next() % 8) << 1; 2]); + let mut expect_conflict = false; + for (i, slot) in model.iter_mut().enumerate() { + if i != index && slot.as_ref().is_some_and(|o| overlaps(&new, o)) { + let mut gone = TlbEntry::new(); + gone.page_mask = slot.as_ref().unwrap().page_mask; + *slot = Some(gone); + expect_conflict = true; + } + } + model[index] = Some(new); + tlb.write(index, new); + assert_eq!(tlb.take_write_conflict(), expect_conflict); + for (i, slot) in model.iter().enumerate() { + let got = tlb.read(i); + let want = slot.unwrap_or_else(TlbEntry::new); + assert_eq!((got.entry_hi, got.entry_lo, got.page_mask), + (want.entry_hi, want.entry_lo, want.page_mask), "entry {i}"); + } + } + } + }).unwrap().join().unwrap(); + } + #[test] fn test_tlb_entry_flags() { let mut entry = TlbEntry::new(); From bddcc3cbee696c3efe023872a2ebf2de057e33b0 Mon Sep 17 00:00:00 2001 From: James Braid Date: Sat, 31 Oct 2026 09:34:16 -0700 Subject: [PATCH 06/11] cpu: complete refused uncached stores on the R10000 family A store that nothing answers raised a synchronous Data Bus Error with a precise PC on every CPU. The R10000 cannot do that. It sends an uncached store as a write request, and a write request gets no response; Bus Error comes only from an error response to a read or upgrade request, or from uncorrectable read data (R10000 UM pp. 104, 316). The processor never learns that a store failed. The R12000 manual documents the same no-response write path, and the later parts are taken to match, so the test is the R10000 family and not the R10000 alone. Add CpuModel::POSTS_UNCACHED_STORES, true for the R10000 family's caches. On such a model a refused store logs and completes in write_data_impl and in the masked-store path (SWL, SWR, SDL, SDR), which the interpreter and the compiled code both go through. An uncached SC or SCD that is refused completes and succeeds (rt = 1); that is a model choice, since the manual says nothing about uncached store-conditional. Loads, instruction fetches, cached accesses and the R4400 and R5000 keep the exception, and device return values are untouched because BUS_ERR also tells non-CPU callers that a request was declined. The error goes no further. Nothing in iris raises an interrupt or sets an error register for a store the Octane's bus refuses. The IP22/IP28 bus already completes a write to an unanswered address, latching MC CPU_ERROR/GIO_ERROR and raising no interrupt, so the stores that change here are the ones a device refuses itself. The log line stays visible ("Unsupported uncached write ... posted, completes") but a probe loop must not flood stderr: it prints the first four refused stores and then each power of two, with the running count. The Octane's ide diagnostics store 0x591204 and then 0x4 to physical 0x1e130400, where nothing answers. Before, the first store took a Data Bus Error; now both print one line and the run carries on. Tests: the interpreter on the R10000 (full and shadow caches) and the R5000 for SW, SWL and SC plus the load that still faults; the JIT against the interpreter for SW and SWL on the R10000 and for the load and the R5000 store that fault; the report schedule. cargo test --release --features jitv2 --lib: 2422 passed, 0 failed. --- CHANGELOG.md | 8 +++++ src/cpu/jitv2/equiv_test.rs | 70 ++++++++++++++++++++++++++++++++++++ src/cpu/mips_cache_shadow.rs | 1 + src/cpu/mips_cache_v2.rs | 9 +++++ src/cpu/mips_exec.rs | 32 ++++++++++++++--- src/cpu/mips_exec_test.rs | 41 +++++++++++++++++++++ 6 files changed, 157 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce5c7d5e5..5a0e90ea6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -196,6 +196,14 @@ hashes are given where a change is easiest to understand by reading the commit. refills through 0x000, as the part does, not 0x080. The R4400 and R5000 still choose by the current mode. +### Refused uncached stores on the R10000 family + +- On the R10000 family (Octane, IP28, O2), an uncached store that nothing answers now + completes instead of raising a Data Bus Error, as the processor does. iris prints + "Unsupported uncached write ... (posted, completes)" for the first four such + stores and then at each power of two. Loads, instruction fetches, the R4400 and + the R5000 are unchanged. + ### `IRIS_GUI_GL` works in iris-gui - The GUI's GL capture path (`IRIS_GUI_GL=1`, or `[debug] gui_gl_capture`) never diff --git a/src/cpu/jitv2/equiv_test.rs b/src/cpu/jitv2/equiv_test.rs index 82ccfcd8d..6370f88d0 100644 --- a/src/cpu/jitv2/equiv_test.rs +++ b/src/cpu/jitv2/equiv_test.rs @@ -7907,4 +7907,74 @@ mod tests { println!("{:<12} {:8.3} ns/instruction", name, ns); } } + + /// R10000: a refused uncached store completes in compiled code exactly as + /// in the interpreter, through both store sites (SW, and SWL by the + /// masked-store helper), and the instructions after it run. The same access + /// as a load, and a store on the R5000, still fault in both engines. + #[test] + fn refused_uncached_store_matches_the_interpreter_on_the_r10000_and_r5000() { + use crate::cpu::mips_cache_v2::{R10000Cache, R5000Cache, CpuModel}; + use crate::cpu::mips_core::STATUS_EXL; + use crate::cpu::mips_isa::{OP_ADDIU, OP_LW, OP_SW, OP_SWL}; + + /// Nothing answers: every read and write is refused (the trait's defaults). + struct RefusingBus; + impl BusDevice for RefusingBus {} + + fn run>>(op: u32) -> (CoreSnapshot, CoreSnapshot) { + let pc = 0xFFFF_FFFF_8000_0000u64; + let mut gpr = [0u64; 32]; + gpr[16] = 0xFFFF_FFFF_A100_0000; // kseg1: uncached, and nothing answers + gpr[6] = 0x1234_5678; + let words = [make_i(op, 16, 6, 0), make_i(OP_ADDIU, 0, 7, 2)]; + let build = || { + let bus: Arc = Arc::new(RefusingBus); + let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); + let mut exec = Box::new(MipsExecutor::::new(bus, PassthroughTlb::default(), &cfg)); + exec.core.gpr = gpr; + exec.core.pc = pc; + exec.core.hot.interrupts.store(0, std::sync::atomic::Ordering::Relaxed); + #[cfg(feature = "fetchverify")] + { exec.core.fetch_verify_on = false; } + exec + }; + let mut interp = build(); + interp.jitv2_dispatch_enabled = false; + for (i, &word) in words.iter().enumerate() { + if interp.core.pc != pc + 4 * i as u64 { + break; // an exception redirected the PC + } + interp.exec(word); + } + + let mut page = [0u32; ENTRIES_PER_PAGE]; + page[..words.len()].copy_from_slice(&words); + let page_base = (pc & !(PAGE_SIZE as u64 - 1)) as u32; + let mut analyzer = Analyzer::new(); + let (walked, non_empty) = analyzer.walk_bounded(&page, 0, page_base, words.len()); + assert!(non_empty); + let mut instrs_owned = *walked; + let mut codegen = Codegen::new(); + let jit_fn: JitFn = codegen.compile_region(&mut instrs_owned, 0, true, false) + .expect("region must be compilable for this test to be meaningful"); + let mut jit = build(); + jit.install_jit_hooks(); + unsafe { jit_fn(&mut jit.core as *mut MipsCore) }; + std::mem::forget(codegen); + (CoreSnapshot::capture(&interp.core), CoreSnapshot::capture(&jit.core)) + } + + for op in [OP_SW, OP_SWL] { + let (interp, jit) = run::(op); + assert_eq!(jit, interp, "op {op:#x}: JIT and interpreter diverged"); + assert_eq!(jit.cp0_status & STATUS_EXL, 0, "op {op:#x}: no exception"); + assert_eq!(jit.gpr[7], 2, "op {op:#x}: the instruction after the store ran"); + } + for (name, (interp, jit)) in [("R10000 load", run::(OP_LW)), ("R5000 store", run::(OP_SW))] { + assert_eq!(jit, interp, "{name}: JIT and interpreter diverged"); + assert_ne!(jit.cp0_status & STATUS_EXL, 0, "{name}: must take its Data Bus Error"); + assert_eq!(jit.gpr[7], 0, "{name}: nothing after the fault ran"); + } + } } diff --git a/src/cpu/mips_cache_shadow.rs b/src/cpu/mips_cache_shadow.rs index 73ab609ba..7047f78ef 100644 --- a/src/cpu/mips_cache_shadow.rs +++ b/src/cpu/mips_cache_shadow.rs @@ -349,6 +349,7 @@ impl< const CACHE_KIND: &'static str = "shadow"; const R10K_FAMILY: bool = Self::R10K_CACHE_OPS; const R10K_CACHE_OPS: bool = MODEL == model::R10000; + const POSTS_UNCACHED_STORES: bool = Self::R10K_CACHE_OPS; } impl< diff --git a/src/cpu/mips_cache_v2.rs b/src/cpu/mips_cache_v2.rs index 8b6b49e15..fd541c82b 100644 --- a/src/cpu/mips_cache_v2.rs +++ b/src/cpu/mips_cache_v2.rs @@ -571,6 +571,14 @@ pub trait CpuModel: MipsCache { /// list of changes from the R10000 has no TLB or CP0 change. The R14000 and /// R16000 are a model choice that gives them the same TLB. const R10K_FAMILY: bool = false; + /// An uncached store the system refuses completes instead of raising a + /// Data Bus Error. The R10000 sends it as a write request, which gets no + /// response, and Bus Error comes only from an error response to a read or + /// upgrade request or from uncorrectable read data (R10000 UM pp. 104, 316). + /// The R12000 manual documents the same path and the later parts are taken + /// to match. An uncached SC succeeding is a model choice. Loads and fetches + /// still fault. + const POSTS_UNCACHED_STORES: bool = false; } pub trait MipsCache: Send + Sync { @@ -3603,6 +3611,7 @@ impl MipsExecutor { self.core.cp0_status |= crate::cpu::mips_core::STATUS_TS & 0u32.wrapping_sub(self.tlb.take_write_conflict() as u32); } + /// An uncached store the system refused, on a model that posts stores + /// (`CpuModel::POSTS_UNCACHED_STORES`): say so and let the store complete. + /// The caller returns `BUS_OK`. Always built, so a missing device or a + /// guest bug stays visible in every build. + #[cold] + fn post_refused_store(&mut self, virt_addr: u64, phys_addr: u64, size: usize, val: u64, status: u32) { + eprintln!("Unsupported uncached write{} (posted, completes): PC={:016x} VA={:016x} PA={:016x} val={:016x} status={:08x}{}", + size * 8, self.core.pc, virt_addr, phys_addr, val, status, self.fault_note(phys_addr, size)); + } + /// Create a new executor from a config and a bus (sysad) and a TLB. /// The cache hierarchy is constructed internally as a unified R4000Cache. pub fn new(sysad: Arc, mut tlb: T, cfg: &MipsCpuConfig) -> Self @@ -5139,9 +5149,16 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", self.sysad.write64(phys_addr, val) }; if ws != BUS_OK && ws != BUS_BUSY && !DEBUG { - eprintln!("Bus error on uncached write{}: PC={:016x} VA={:016x} PA={:016x} val={:016x} status={:08x}{}", SIZE*8, self.core.pc, virt_addr, phys_addr, val, ws, self.fault_note(phys_addr, SIZE)); + if C::POSTS_UNCACHED_STORES { + self.post_refused_store(virt_addr, phys_addr, SIZE, val, ws); + BUS_OK + } else { + eprintln!("Bus error on uncached write{}: PC={:016x} VA={:016x} PA={:016x} val={:016x} status={:08x}{}", SIZE*8, self.core.pc, virt_addr, phys_addr, val, ws, self.fault_note(phys_addr, SIZE)); + ws + } + } else { + ws } - ws }; // jitv2_lockstep's load/store verification (see MipsCore's // lockstep_mem field doc comment, and read_data_impl's matching @@ -5195,9 +5212,16 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", } let ws = self.sysad.write64_masked(phys_addr, val, mask); if ws != BUS_OK && ws != BUS_BUSY && !DEBUG { - eprintln!("Bus error on uncached write64_masked: PC={:016x} VA={:016x} PA={:016x} val={:016x} mask={:016x} status={:08x}{}", self.core.pc, virt_addr, phys_addr, val, mask, ws, self.fault_note(phys_addr, 8)); + if C::POSTS_UNCACHED_STORES { + self.post_refused_store(virt_addr, phys_addr, mask.count_ones() as usize / 8, val, ws); + BUS_OK + } else { + eprintln!("Bus error on uncached write64_masked: PC={:016x} VA={:016x} PA={:016x} val={:016x} mask={:016x} status={:08x}{}", self.core.pc, virt_addr, phys_addr, val, mask, ws, self.fault_note(phys_addr, 8)); + ws + } + } else { + ws } - ws } } diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index afc15cf7b..83be91af4 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -6735,4 +6735,45 @@ mod tests { check::(true); }); } + + /// A bus where nothing answers: every read and write is refused (the + /// trait's defaults). + struct RefusingBus; + impl BusDevice for RefusingBus {} + + /// R10000: a store the system refuses leaves the processor as a write + /// request, which has no response, so it completes (R10000 UM pp. 104, + /// 316). An uncached SC succeeding is a model choice. A load keeps its + /// Data Bus Error, and so does every access on the R5000. SWL goes through + /// the masked-store path, a separate site. + #[test] + fn refused_uncached_store_completes_only_on_the_r10000() { + fn run>>(op: u32) -> (u32, u64) { + let bus: Arc = Arc::new(RefusingBus); + let mut exec = MipsExecutor::::new(bus, PassthroughTlb::default(), &MipsCpuConfig::indy()); + disable_jitv2(&mut exec); + exec.cache.set_llbit(true); + exec.core.write_gpr(4, 0xFFFF_FFFF_A100_0000); // kseg1: uncached + exec.core.write_gpr(6, 0x1234_5678); + let st = exec.exec(make_i(op, 4, 6, 4)); + if st == EXEC_COMPLETE { + assert_eq!(exec.core.cp0_status & crate::cpu::mips_core::STATUS_EXL, 0, "no exception taken"); + assert_eq!(exec.exec(make_i(OP_ADDIU, 0, 5, 7)), EXEC_COMPLETE); + assert_eq!(exec.core.read_gpr(5), 7, "the next instruction runs"); + } + (st, exec.core.read_gpr(6)) + } + use crate::traits::BUS_ERR; + type R10K = crate::cpu::mips_cache_v2::R10000Cache; + type R10KShadow = crate::cpu::mips_cache_shadow::R10000ShadowCache; + type R5K = crate::cpu::mips_cache_shadow::R5000ShadowCache; + for (op, name) in [(OP_SW, "SW"), (OP_SWL, "SWL")] { + assert_eq!(run::(op).0, EXEC_COMPLETE, "R10000 {name}"); + assert_eq!(run::(op).0, EXEC_COMPLETE, "R10000 shadow {name}"); + assert_eq!(run::(op).0, BUS_ERR, "R5000 {name}"); + } + assert_eq!(run::(OP_SC), (EXEC_COMPLETE, 1), "SC succeeds"); + assert_eq!(run::(OP_SC).0, BUS_ERR, "R5000 SC"); + assert_eq!(run::(OP_LW).0, BUS_ERR, "a refused load still faults"); + } } From 2ce38482ef2f79952691749a50333c9c956f9a0b Mon Sep 17 00:00:00 2001 From: James Braid Date: Fri, 30 Oct 2026 05:16:09 -0700 Subject: [PATCH 07/11] cpu: match the O2 memory alias after the physical address mask A mapped page whose physical address has a bit set above bit 31 could reach the PCI window instead of RAM on the O2. The O2 aliases RAM at 0x8000_0000, and fold_phys tested that window on the full translated address before cutting it to the 32 bits the board decodes. IRIX keeps software bits in its page-table entries just above the PFN, so such an address missed the window, then lost the high bit in the mask and landed on the PCI range at 0x8000_0000. Cut to the decoded bits first, then apply the alias, then cut its target. The window lies within the decoded bits, so a page already inside it lands where it did. The extra AND runs only on an alias hit. Only the O2 has a physical alias; the Indy, Indigo2 and Octane are unchanged. A test maps a page at 0x1_8000_0000 with the O2's mask and window and expects RAM at 0. It reads 0x8000_0000 without the fix. --- CHANGELOG.md | 3 +++ src/cpu/mips_exec.rs | 18 ++++++++++-------- src/cpu/mips_exec_test.rs | 25 +++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a0e90ea6..f1a7f8dc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -603,6 +603,9 @@ hashes are given where a change is easiest to understand by reading the commit. ### SGI O2 (IP32) +- **The O2's memory alias holds for pages with high PTE bits set.** A mapped page + whose address had a bit set above bit 31 missed the alias of RAM at + 0x8000_0000 and reached the PCI window instead. - **The O2 runs on the shadow cache from reset.** The full cache model, and the switch to and from it during POST and reboots, are gone (`src/ip32_handover.rs`), and with them a branch on every cached load, store diff --git a/src/cpu/mips_exec.rs b/src/cpu/mips_exec.rs index 57441c76d..176351ef9 100644 --- a/src/cpu/mips_exec.rs +++ b/src/cpu/mips_exec.rs @@ -1032,12 +1032,12 @@ pub struct MipsExecutor { pub batch_hook: Option) + Send>>, /// A window of physical addresses that reaches memory at another address, /// `(base, size, target)`, applied to mapped and XKPHYS translations - /// before [`Self::phys_mask`]. The O2 has a no-ECC alias of its memory at + /// after [`Self::phys_mask`]. The O2 has a no-ECC alias of its memory at /// 0x8000_0000 that would otherwise reach the PCI window the bus decodes /// there. None on the other machines. pub phys_alias: Option<(u64, u64, u64)>, /// The physical address bits the board decodes, applied to mapped, - /// XKPHYS and ERL-identity translations after [`Self::phys_alias`]. The + /// XKPHYS and ERL-identity translations before [`Self::phys_alias`]. The /// CPU drives 36 or 40 bits, but the Indy, Indigo2 and O2 decode 32 and /// alias the rest away, and IRIX relies on it: its page-table entries keep /// software bits (the PFN lock among them) just above the PFN, so they @@ -4664,15 +4664,17 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", } } - /// A CPU physical address as the board decodes it: through - /// [`Self::phys_alias`] if it falls in it, then cut to [`Self::phys_mask`]. + /// A CPU physical address as the board decodes it: cut to + /// [`Self::phys_mask`], then through [`Self::phys_alias`] if it falls in it. #[inline(always)] fn fold_phys(&self, pa: u64) -> u64 { - let pa = match self.phys_alias { - Some((base, size, target)) if pa.wrapping_sub(base) < size => pa - base + target, + // Cut first: the PTE software bits above the PFN are not part of the + // address the alias window sees. Window and target lie within the mask. + let pa = pa & self.phys_mask; + match self.phys_alias { + Some((base, size, target)) if pa.wrapping_sub(base) < size => (pa - base + target) & self.phys_mask, _ => pa, - }; - pa & self.phys_mask + } } /// TLB translation. When `DEBUG` is true, CP0 side-effect registers are diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index 83be91af4..af26ed525 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -6776,4 +6776,29 @@ mod tests { assert_eq!(run::(OP_SC).0, BUS_ERR, "R5000 SC"); assert_eq!(run::(OP_LW).0, BUS_ERR, "a refused load still faults"); } + + /// The O2's no-ECC alias of RAM at 0x8000_0000 is matched on the address the + /// board decodes (32 bits), so a PTE software bit above the PFN cannot make + /// a mapped page miss the alias window. + #[test] + fn phys_alias_is_matched_after_the_physical_mask() { + std::thread::Builder::new() + .stack_size(16 * 1024 * 1024) + .spawn(|| { + use crate::cpu::mips_tlb::MipsTlb; + let (mut exec, _) = create_executor_with_tlb(MipsTlb::default()); + exec.core.cp0_status &= !crate::cpu::mips_core::STATUS_ERL; + exec.phys_mask = u32::MAX as u64; + exec.phys_alias = Some((0x8000_0000, 0x1000_0000, 0)); + // PA 0x1_8000_0000: bit 32 is above what the board decodes. + exec.core.cp0_index = 0; + exec.core.cp0_pagemask = 0; + exec.core.cp0_entryhi = 0x4000_0000; + exec.core.cp0_entrylo0 = (0x18_0000 << 6) | (3 << 3) | (1 << 2) | (1 << 1); + exec.core.cp0_entrylo1 = 0; + assert_eq!(exec.exec((OP_COP0 << 26) | (0x10 << 21) | 0x02), EXEC_COMPLETE); + assert_eq!(exec.debug_translate(0x4000_0000).phys, 0); + }) + .unwrap().join().unwrap(); + } } From 2b3fae6b3e3d43a5ef99564da1bf6ccd7a664e66 Mon Sep 17 00:00:00 2001 From: James Braid Date: Fri, 30 Oct 2026 08:03:24 +0000 Subject: [PATCH 08/11] cpu: keep the upper word on a partial LWR on the R10000 In 64-bit mode a partial LWR (offset 0 to 2) sign-extended the merged word on every CPU. The manual calls the upper word of a partial LWR implementation specific (NEC U12754E pp. 125-126), and the reference results observed for the R10000 keep the old bits 63:32 at all three partial offsets. With sign extension a test that compares those results miscompares. The interpreter and the JIT now merge the old upper word on the R10000; a full word (offset 3) still sign-extends. The upper word is kept only when 64-bit operations are enabled for the current mode, matching QEMU; otherwise it sign-extends. The later parts are not covered, since nothing shows what they do. The choice is a JitConsts field set from CpuModel::PARTIAL_LWR_KEEPS_UPPER, so compile workers see it. Whether 64-bit operations are on is a byte in the core that the executor sets wherever it re-derives the privilege state, so a compiled LWR spends a byte load and a compare on it rather than decoding Status; the merge runs on the whole register and needs no more work than the old sign-extending sequence. The code-cache fingerprint gains lwr_upper=1 only when it is set, so the R4400 and R5000 machines keep their warm caches. Behaviour changes on the Octane, IP28 and an O2 with the R10000. The R4400 and R5000 are unchanged. Tests run LWR at every offset in the interpreter on the R4400, R5000 and R10000 in kernel, supervisor and user mode with the mode's own 64-bit bit set and clear, run the same offsets as compiled code on the R10000 and R5000 and compare with the interpreter, and check the fingerprint. --- CHANGELOG.md | 8 +++ src/cpu/jitv2/codegen.rs | 51 +++++++++++++++++ src/cpu/jitv2/equiv_test.rs | 103 +++++++++++++++++++++++++++++++++++ src/cpu/jitv2/mod.rs | 1 + src/cpu/mips_cache_shadow.rs | 1 - src/cpu/mips_cache_v2.rs | 7 ++- src/cpu/mips_core.rs | 2 + src/cpu/mips_exec.rs | 15 ++++- src/cpu/mips_exec_test.rs | 74 +++++++++++++++++++++++++ 9 files changed, 257 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1a7f8dc0..1f65306ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -204,6 +204,14 @@ hashes are given where a change is easiest to understand by reading the commit. stores and then at each power of two. Loads, instruction fetches, the R4400 and the R5000 are unchanged. +### Partial LWR on the R10000 + +- On the R10000 (Octane, IP28, and an O2 with the R10000), an `LWR` that loads fewer + than four bytes now keeps bits 63:32 of the destination instead of sign-extending, + as the reference results for the part show. R4400 and R5000 machines are unchanged. + The JIT matches the interpreter, and the code-cache key changes only for the + machines that have the behaviour. + ### `IRIS_GUI_GL` works in iris-gui - The GUI's GL capture path (`IRIS_GUI_GL=1`, or `[debug] gui_gl_capture`) never diff --git a/src/cpu/jitv2/codegen.rs b/src/cpu/jitv2/codegen.rs index 30a6c9777..16b3ec809 100644 --- a/src/cpu/jitv2/codegen.rs +++ b/src/cpu/jitv2/codegen.rs @@ -868,6 +868,10 @@ impl Codegen { for v in isa.isa_flags() { let _ = write!(s, " {v}"); } + // Only when set, so machines without the behaviour keep their warm cache. + if self.jit_consts.lwr_keeps_upper { + s.push_str(" lwr_upper=1"); + } s.push_str(" ops="); s.extend(crate::cpu::jitv2::opcode_support::enabled_snapshot().iter().map(|&b| if b { '1' } else { '0' })); Some(blake3::hash(s.as_bytes()).as_bytes()[..16].try_into().unwrap()) @@ -4377,6 +4381,11 @@ pub struct JitConsts { /// to loading from memory, exactly as before, so an un-stamped `Codegen` /// stays correct (just no faster). pub core: Option, + /// A partial LWR keeps bits 63:32 of the destination, as the R10000 + /// does (`CpuModel::PARTIAL_LWR_KEEPS_UPPER`). A model fact rather than a + /// core one, published beside the core address because both reach a worker's + /// `Codegen` the same way. The code-cache fingerprint carries it when set. + pub lwr_keeps_upper: bool, } impl JitConsts { @@ -10005,6 +10014,31 @@ fn emit_lwl_ldl(ctx: &mut EmitCtx, size: MemSize) { emit_write_gpr(ctx, field_rt(ctx.raw), result); } +/// LWR on a model whose partial LWR keeps rt[63:32] (`lwr_keeps_upper`), +/// mirroring `MipsExecutor::exec_lwr`: offsets 0 to 2 keep the upper word while +/// 64-bit operations are on, anything else sign-extends the merged low half. +/// `core.lwr_upper_below` makes that one compare. `loaded` is the aligned word. +fn emit_lwr_keeping_upper(ctx: &mut EmitCtx, loaded: Value, byte_offset: Value) { + let i64t = ir::types::I64; + // Bytes of the word the register keeps: 8 * (3 - offset). + let inverted = ctx.builder.ins().bxor_imm_s(byte_offset, 3); + let shift = ctx.builder.ins().ishl_imm_s(inverted, 3); + let ones = ctx.builder.ins().iconst(i64t, 0xFFFF_FFFF); + let mask = ctx.builder.ins().ushr(ones, shift); + let shifted_mem = ctx.builder.ins().ushr(loaded, shift); + let rt_val = emit_read_gpr(ctx, field_rt(ctx.raw)); + let not_mask = ctx.builder.ins().bnot(mask); + let preserved = ctx.builder.ins().band(rt_val, not_mask); + let merged = ctx.builder.ins().bor(shifted_mem, preserved); + let low = ctx.builder.ins().ireduce(ir::types::I32, merged); + let sign_extended = ctx.builder.ins().sextend(i64t, low); + let below_off = ir::immediates::Offset32::new(std::mem::offset_of!(MipsCore, lwr_upper_below) as i32); + let below = ctx.builder.ins().uload8(i64t, MemFlagsData::trusted(), ctx.core_ptr, below_off); + let keep = ctx.builder.ins().icmp(IntCC::UnsignedLessThan, byte_offset, below); + let result = ctx.builder.ins().select(keep, merged, sign_extended); + emit_write_gpr(ctx, field_rt(ctx.raw), result); +} + /// LWR rt, imm(rs) / LDR rt, imm(rs): load the "right" (low-address-end) /// portion — the mirror-image shift direction of [`emit_lwl_ldl`], see that /// function's doc comment for the shared shape. Mirrors @@ -10022,6 +10056,11 @@ fn emit_lwr_ldr(ctx: &mut EmitCtx, size: MemSize) { let loaded = emit_mem_read(ctx, aligned_addr, size); + if size == MemSize::B4 && ctx.jit_consts.lwr_keeps_upper { + emit_lwr_keeping_upper(ctx, loaded, byte_offset); + return; + } + let ity = size.ir_type(); let mem_val = if size == MemSize::B8 { loaded } else { ctx.builder.ins().ireduce(ity, loaded) }; let rt_val = emit_read_gpr(ctx, field_rt(ctx.raw)); @@ -10809,6 +10848,18 @@ mod tests { (op << 26) | (rs << 21) | (rt << 16) | (rd << 11) | (sa << 6) | funct } + #[test] + fn cache_fingerprint_includes_the_lwr_choice() { + let base = Codegen::new().cache_fingerprint(false).expect("default codegen is cacheable"); + let mut codegen = Codegen::new(); + codegen.jit_consts.lwr_keeps_upper = true; + assert_ne!( + codegen.cache_fingerprint(false).expect("lwr codegen is cacheable"), + base, + "the LWR choice must select a different persistent cache namespace", + ); + } + /// `is_inlinable` must reject on *both* of its conditions, not just the /// bounds one. The bounds half is what panicked /// (`clanker/jitv2/nested-delay-slot-across-page-boundary.md`); the diff --git a/src/cpu/jitv2/equiv_test.rs b/src/cpu/jitv2/equiv_test.rs index 6370f88d0..ea580594b 100644 --- a/src/cpu/jitv2/equiv_test.rs +++ b/src/cpu/jitv2/equiv_test.rs @@ -4383,6 +4383,109 @@ mod tests { } } + /// Run `words` from `pc` once through the interpreter and once as a + /// compiled region, both on CPU model `C` over a fresh `bus()` and seeded + /// with `gpr` and CP0 Status `status`. The JIT learns the model's choices from `install_jit_hooks`, + /// as in production. + fn interpreter_and_jit(bus: impl Fn() -> Arc, pc: u64, gpr: [u64; 32], status: u32, words: &[u32]) + -> (CoreSnapshot, CoreSnapshot) + where + C: crate::cpu::mips_cache_v2::CpuModel + From>, + { + let build = || { + let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); + let mut exec = Box::new(MipsExecutor::::new(bus(), PassthroughTlb::default(), &cfg)); + exec.core.gpr = gpr; + exec.core.pc = pc; + exec.set_cp0_status(status); + exec.core.hot.interrupts.store(0, std::sync::atomic::Ordering::Relaxed); + #[cfg(feature = "fetchverify")] + { exec.core.fetch_verify_on = false; } + exec + }; + let mut interp = build(); + interp.jitv2_dispatch_enabled = false; + for (i, &word) in words.iter().enumerate() { + if interp.core.pc != pc + 4 * i as u64 { + break; // an exception redirected the PC + } + interp.exec(word); + } + + let mut page = [0u32; ENTRIES_PER_PAGE]; + page[..words.len()].copy_from_slice(words); + let page_base = (pc & !(PAGE_SIZE as u64 - 1)) as u32; + let mut analyzer = Analyzer::new(); + let (walked, non_empty) = analyzer.walk_bounded(&page, 0, page_base, words.len()); + assert!(non_empty); + let mut instrs_owned = *walked; + let mut codegen = Codegen::new(); + codegen.jit_consts.lwr_keeps_upper = C::PARTIAL_LWR_KEEPS_UPPER; + let jit_fn: JitFn = codegen.compile_region(&mut instrs_owned, 0, true, false) + .expect("region must be compilable for this test to be meaningful"); + let mut jit = build(); + jit.install_jit_hooks(); + // The compile pool's workers read the model's choice from here, so a + // missing publication would not show if `codegen` were stamped by hand. + assert_eq!(jit.jitv2.lock().jit_consts.lock().lwr_keeps_upper, C::PARTIAL_LWR_KEEPS_UPPER); + unsafe { jit_fn(&mut jit.core as *mut MipsCore) }; + std::mem::forget(codegen); + (CoreSnapshot::capture(&interp.core), CoreSnapshot::capture(&jit.core)) + } + + /// The R10000 keeps bits 63:32 on a partial LWR while 64-bit operations are + /// enabled for the current mode and the R5000 sign-extends; with them off + /// (a 32-bit user process, UX=0) the R10000 sign-extends too. The JIT and + /// the interpreter must agree at every offset in every mode, and the + /// interpreter's result is the one `partial_lwr_keeps_the_upper_word_only_on_the_r10000` + /// pins. + #[test] + fn jit_lwr_matches_the_interpreter_on_the_r10000_and_r5000() { + use crate::cpu::mips_cache_shadow::{R10000ShadowCache, R5000ShadowCache}; + fn check>>(model_keeps_upper: bool) { + use crate::cpu::mips_core::{STATUS_ERL, STATUS_EXL, STATUS_KX, STATUS_SX, STATUS_UX}; + const RESERVED: u32 = 3 << 3; + const USER: u32 = 2 << 3; + const SUPER: u32 = 1 << 3; + // (Status, whether 64-bit operations are on): each mode's own + // bit decides, whatever the other two hold. + for (status, ops64, mode) in [ + (STATUS_KX, true, "kernel KX=1"), + (0, false, "kernel KX=0"), + (STATUS_UX | STATUS_SX, false, "kernel KX=0, UX/SX=1"), + (USER | STATUS_UX, true, "user UX=1"), + (USER | STATUS_KX | STATUS_SX, false, "user UX=0, KX/SX=1"), + (SUPER | STATUS_SX, true, "supervisor SX=1"), + (SUPER | STATUS_KX | STATUS_UX, false, "supervisor SX=0"), + (USER | STATUS_EXL | STATUS_KX, true, "EXL forces kernel, KX=1"), + (USER | STATUS_EXL | STATUS_UX, false, "EXL forces kernel, UX=1 KX=0"), + (SUPER | STATUS_ERL | STATUS_KX, true, "ERL forces kernel, KX=1"), + (SUPER | STATUS_ERL | STATUS_SX, false, "ERL forces kernel, SX=1 KX=0"), + (RESERVED | STATUS_KX, true, "reserved KSU counts as kernel, KX=1"), + (RESERVED | STATUS_UX | STATUS_SX, false, "reserved KSU counts as kernel, KX=0"), + ] { + for offset in 0..4u64 { + let mut gpr = [0u64; 32]; + gpr[1] = 0x2000 + offset; + gpr[2] = 0x1122_3344_5566_7788; + let bus = || -> Arc { + let mem = Arc::new(MockMemory::new_not_compilable()); + mem.set_word(0x2000, 0xDEAD_BEEF); + mem + }; + let lwr = make_i(crate::cpu::mips_isa::OP_LWR, 1, 2, 0); + let (interp, jit) = interpreter_and_jit::(bus, 0x1000, gpr, status, &[lwr]); + assert_eq!(jit, interp, "{} JIT/interpreter LWR offset {offset}, {mode}", C::NAME); + let upper_kept = interp.gpr[2] >> 32 == 0x1122_3344; + assert_eq!(upper_kept, model_keeps_upper && ops64 && offset != 3, + "{} LWR offset {offset}, {mode}", C::NAME); + } + } + } + check::(true); + check::(false); + } + #[test] fn lwl_lwr_combine_to_a_full_unaligned_word_load_matches_interpreter() { // The canonical compiler-generated idiom for an unaligned word diff --git a/src/cpu/jitv2/mod.rs b/src/cpu/jitv2/mod.rs index 43e49a7b7..576246911 100644 --- a/src/cpu/jitv2/mod.rs +++ b/src/cpu/jitv2/mod.rs @@ -92,6 +92,7 @@ mod zz_corpus { // (baked immediate vs load) is identical to production. crate::cpu::jitv2::codegen::JitConsts { core: core::num::NonZeroUsize::new(core as *mut MipsCore as usize), + ..Default::default() } }; // Synthetic corpus-measurement geometry: 16 KiB direct-mapped L1-D diff --git a/src/cpu/mips_cache_shadow.rs b/src/cpu/mips_cache_shadow.rs index 7047f78ef..73ab609ba 100644 --- a/src/cpu/mips_cache_shadow.rs +++ b/src/cpu/mips_cache_shadow.rs @@ -349,7 +349,6 @@ impl< const CACHE_KIND: &'static str = "shadow"; const R10K_FAMILY: bool = Self::R10K_CACHE_OPS; const R10K_CACHE_OPS: bool = MODEL == model::R10000; - const POSTS_UNCACHED_STORES: bool = Self::R10K_CACHE_OPS; } impl< diff --git a/src/cpu/mips_cache_v2.rs b/src/cpu/mips_cache_v2.rs index fd541c82b..7140311e6 100644 --- a/src/cpu/mips_cache_v2.rs +++ b/src/cpu/mips_cache_v2.rs @@ -571,6 +571,10 @@ pub trait CpuModel: MipsCache { /// list of changes from the R10000 has no TLB or CP0 change. The R14000 and /// R16000 are a model choice that gives them the same TLB. const R10K_FAMILY: bool = false; + /// A partial LWR keeps bits 63:32 of the destination. Observed on the + /// R10000; whether the later parts do the same is not established, so they + /// keep the sign extension for now. + const PARTIAL_LWR_KEEPS_UPPER: bool = Self::R10K_FAMILY; /// An uncached store the system refuses completes instead of raising a /// Data Bus Error. The R10000 sends it as a write request, which gets no /// response, and Bus Error comes only from an error response to a read or @@ -578,7 +582,7 @@ pub trait CpuModel: MipsCache { /// The R12000 manual documents the same path and the later parts are taken /// to match. An uncached SC succeeding is a model choice. Loads and fetches /// still fault. - const POSTS_UNCACHED_STORES: bool = false; + const POSTS_UNCACHED_STORES: bool = Self::R10K_FAMILY; } pub trait MipsCache: Send + Sync { @@ -3611,7 +3615,6 @@ impl MipsExecutor { // set) -- the property a persistent code cache needs. // Several CPUs share compiled code, so no one core's address. core: if self.core.smp || std::env::var_os("IRIS_JIT_PIC").is_some() { None } else { core::num::NonZeroUsize::new(core_addr) }, + lwr_keeps_upper: C::PARTIAL_LWR_KEEPS_UPPER, }; *j.jit_consts.lock() = consts; // The inline-compile path (`jitv2_compile_inline`) takes this @@ -3269,6 +3270,7 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", pub fn update_translate_fn(&mut self) { use crate::cpu::mips_core::PrivilegeMode; let is_64bit = self.core.is_64bit_mode(); + self.core.lwr_upper_below = if C::PARTIAL_LWR_KEEPS_UPPER && is_64bit { 3 } else { 0 }; let privilege = self.core.get_privilege_mode(); self.translate_fn = match (is_64bit, privilege) { (false, PrivilegeMode::Kernel) => translate_32_kernel::, @@ -6441,8 +6443,17 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", let mask = 0xFFFFFFFFu32 >> shift; let result = (mem_word >> shift) | (rt_val & !mask); - // Sign-extend to 64 bits - self.core.write_gpr(rt_reg, result as i32 as i64 as u64); + // The manual leaves the upper word of a partial LWR + // implementation specific (NEC U12754E pp. 125-126); the R10000 + // keeps bits 63:32. A full word, or any word with 64-bit + // operations off, sign-extends. `lwr_upper_below` folds both. + let value = if C::PARTIAL_LWR_KEEPS_UPPER && (byte_offset as u8) < self.core.lwr_upper_below { + (self.core.read_gpr(rt_reg) & 0xffff_ffff_0000_0000) | result as u64 + } else { + // Sign-extend to 64 bits + result as i32 as i64 as u64 + }; + self.core.write_gpr(rt_reg, value); self.handle_exec_complete() } Err(status) => self.finish_status(status) diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index af26ed525..75c11ab4f 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -6801,4 +6801,78 @@ mod tests { }) .unwrap().join().unwrap(); } + + /// A partial LWR keeps bits 63:32 of the destination on the R10000 while + /// 64-bit operations are enabled for the current mode, and sign-extends on + /// the R4400 and R5000 and on the R10000 when they are off (a 32-bit user + /// process, UX=0); a complete word sign-extends on all. + /// Compiled LWR reads `core.lwr_upper_below` rather than decoding Status, + /// so it must follow `is_64bit_mode()` through a Status write and through + /// ERET, which changes the mode without writing Status, and stay 0 on a + /// model that does not keep the upper word. + #[test] + fn lwr_upper_below_follows_the_mode_through_status_writes_and_eret() { + use crate::cpu::mips_core::{STATUS_EXL, STATUS_UX}; + fn check>>(keeps_upper: bool) { + let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); + let mut exec = Box::new(MipsExecutor::::new( + Arc::new(MockMemory::new()), PassthroughTlb::default(), &cfg)); + disable_jitv2(&mut exec); + let expect = |exec: &MipsExecutor| { + if keeps_upper && exec.core.is_64bit_mode() { 3 } else { 0 } + }; + for status in 0..=0xffu32 { + exec.set_cp0_status(status); + assert_eq!(exec.core.lwr_upper_below, expect(&exec), "{} Status {status:#x}", C::NAME); + } + exec.set_cp0_status((2 << 3) | STATUS_UX | STATUS_EXL); + assert_eq!(exec.core.lwr_upper_below, 0, "EXL forces kernel mode, where KX is clear"); + exec.core.cp0_epc = 0x1000; + assert_eq!(exec.exec(0x4200_0018), EXEC_COMPLETE, "ERET"); + assert_eq!(exec.core.lwr_upper_below, if keeps_upper { 3 } else { 0 }, "ERET returns to user mode with UX set"); + } + check::(true); + check::(false); + } + + #[test] + fn partial_lwr_keeps_the_upper_word_only_on_the_r10000() { + use crate::cpu::mips_core::{STATUS_KX, STATUS_SX, STATUS_UX}; + const USER: u32 = 2 << 3; + const SUPER: u32 = 1 << 3; + fn check>>(model_keeps_upper: bool) { + let mem = Arc::new(MockMemory::new()); + mem.set_word(0x2000, 0x89ab_cdef); + let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); + let mut exec = Box::new(MipsExecutor::::new(mem, PassthroughTlb::default(), &cfg)); + disable_jitv2(&mut exec); + exec.core.write_gpr(1, 0x2000); + let old = 0x8123_4567_a1b2_c3d4u64; + // (Status, 64-bit operations on): each mode's own bit decides, + // whatever the other two hold. + for (status, ops64, mode) in [ + (STATUS_KX, true, "kernel KX=1"), + (0, false, "kernel KX=0"), + (USER | STATUS_UX, true, "user UX=1"), + (USER | STATUS_KX | STATUS_SX, false, "user UX=0"), + (SUPER | STATUS_SX, true, "supervisor SX=1"), + (SUPER | STATUS_KX | STATUS_UX, false, "supervisor SX=0"), + ] { + exec.set_cp0_status(status); + for (offset, word) in [0xa1b2_c389u32, 0xa1b2_89ab, 0xa189_abcd, 0x89ab_cdef].into_iter().enumerate() { + exec.core.write_gpr(2, old); + assert_eq!(exec.exec(make_i(OP_LWR, 1, 2, offset as u16)), EXEC_COMPLETE); + let expected = if model_keeps_upper && ops64 && offset != 3 { + (old & 0xffff_ffff_0000_0000) | word as u64 + } else { + word as i32 as i64 as u64 + }; + assert_eq!(exec.core.read_gpr(2), expected, "{} LWR offset {offset}, {mode}", C::NAME); + } + } + } + check::(false); + check::(false); + check::(true); + } } From 5de55345dfe1c76d97018b350cb819a489ca9d21 Mon Sep 17 00:00:00 2001 From: James Braid Date: Fri, 30 Oct 2026 08:03:24 +0000 Subject: [PATCH 09/11] cpu: keep primary-cache diagnostic data on the R10000 A PROM's cache walk reads and writes the primary caches with Index Load Data and Index Store Data. Only the secondary cache had a data array, so an Index Load Data on a primary cache always returned zero and an Index Store Data was dropped. Give the primary caches data arrays and mask each store to its diagnostic field (R10000 UM pp. 262, 271-272): 36 data bits and 1 parity bit for the instruction cache, 32 and 4 for the data cache, 64 and 10 for the secondary. An Index Store Data to the secondary cache writes a quadword, so the other doubleword becomes zero and takes the same check bits (p. 91). A mapped primary Index Load Data or Index Store Data still takes TLB Refill and Invalid, so CACHE now translates the operand for those two; the other index operations still do not. The secondary data slot is now the address >> 3 where it was >> 4, so the walk gets one slot per doubleword instead of two doublewords sharing one. This affects the Octane, the IP28 and an O2 with an R10000. Tests cover a primary round trip and the quadword store. Index Store Data is a diagnostic walk's operation, so it runs out of line in a cold function, and CACHE tests the primary-cache pair against a bit mask. Written inline they grew cache_op and exec_cache in every CPU model and moved the interpreter's hot loops, which cost sys/llsc about 2% on a ship build. --- CHANGELOG.md | 6 ++ src/cpu/mips_cache_shadow.rs | 95 ++++++++++++++++++++++-------- src/cpu/mips_cache_v2.rs | 110 +++++++++++++++++++++++++++++++++++ src/cpu/mips_exec.rs | 31 ++++------ 4 files changed, 200 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f65306ec..e0d8352de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -212,6 +212,12 @@ hashes are given where a change is easiest to understand by reading the commit. The JIT matches the interpreter, and the code-cache key changes only for the machines that have the behaviour. +### R10000 cache operations + +- **Index Load Data and Index Store Data** on the R10000's primary caches keep their + data (they read back zero before). The secondary cache's data slot is the address + shifted right by 3 instead of 4: one slot per doubleword. + ### `IRIS_GUI_GL` works in iris-gui - The GUI's GL capture path (`IRIS_GUI_GL=1`, or `[debug] gui_gl_capture`) never diff --git a/src/cpu/mips_cache_shadow.rs b/src/cpu/mips_cache_shadow.rs index 73ab609ba..4c68e2da8 100644 --- a/src/cpu/mips_cache_shadow.rs +++ b/src/cpu/mips_cache_shadow.rs @@ -204,11 +204,11 @@ impl< lladdr: UnsafeCell::new(0), ecc_in: UnsafeCell::new(0), ecc_out: UnsafeCell::new(0), - ic: UnsafeCell::new(Shadow::new(Self::IC_LINES, 0)), - dc: UnsafeCell::new(Shadow::new(Self::DC_LINES, 0)), - // Only the R10000 secondary keeps a data shadow: it is the one - // the IP28 PROM walks with Index_Store_Data, and a 1 MB array is - // cheap once. The R4000 family has no index data ops. + // The R10000 keeps data arrays for all three caches, for the PROM's + // Index_Load_Data / Index_Store_Data walks. The R4000 family has no + // index data ops. + ic: UnsafeCell::new(Shadow::new(Self::IC_LINES, if Self::R10K { IC_SIZE / 4 } else { 0 })), + dc: UnsafeCell::new(Shadow::new(Self::DC_LINES, if Self::R10K { DC_SIZE / 4 } else { 0 })), l2: UnsafeCell::new(Shadow::new(Self::L2_LINES, if Self::R10K { L2_SIZE / 8 } else { 0 })), tc_base: UnsafeCell::new(std::ptr::null_mut()), tc_bitmap: UnsafeCell::new(0), @@ -296,17 +296,54 @@ impl< /// Data slot for an R10000 `Index_Load_Data` / `Index_Store_Data`. /// - /// Same shape: way in bit 0, the rest addressing the array. The PROM walks - /// it at `…00`, `…01`, `…10`, `…11`, `…20` — one doubleword per operation - /// with the way bit shifted in beneath it. - fn data_slot(&self, len: usize, virt_addr: u64) -> usize { + /// Same shape: way in bit 0, the rest addressing the array, with four-byte + /// primary and eight-byte secondary slots. This is a model choice, enough + /// for a data walk to read back what it wrote. + fn data_slot(&self, sel: u32, len: usize, virt_addr: u64) -> usize { if len == 0 { return 0; } let way = (virt_addr as usize) & (WAYS - 1); - let word = (virt_addr as usize) >> 4; + let shift = if matches!(sel, CACH_PI | CACH_PD) { 2 } else { 3 }; + let word = (virt_addr as usize) >> shift; (word * WAYS + way) % len } + + /// R10000 `Index_Store_Data`, kept out of line: it runs only in a PROM's + /// diagnostic walk, and inlining it grew `cache_op` and moved the code + /// laid out after it. + #[cold] + #[inline(never)] + fn index_store_data(&self, sel: u32, virt_addr: u64, phys_addr: u64) { + let s = self.shadow(sel); + if s.data.is_empty() { + return; + } + let slot = self.data_slot(sel, s.data.len(), virt_addr); + // Diagnostic field widths: R10000 UM pp. 262, 271-272. + let (data_mask, ecc_mask) = if sel == CACH_PI { + (0xf_ffff_ffff, 1) + } else if sel == CACH_PD { + (0xffff_ffff, 0xf) + } else { + (u64::MAX, 0x3ff) + }; + let ecc = unsafe { *self.ecc_in.get() } & ecc_mask; + s.data[slot] = phys_addr & data_mask; + s.ecc[slot] = ecc; + if matches!(sel, CACH_SI | CACH_SD) { + // Index Store Data (S) writes a quadword: the selected + // doubleword plus a zero partner, sharing the check bits + // (R10000 UM p. 91, figure 5-7). + let partner = slot ^ WAYS; + s.data[partner] = 0; + s.ecc[partner] = ecc; + } + if l2_op_log(CACHE_LOG_HIT) { + crate::dlog!(LogModule::L2c, "shadow: -> ISD slot={slot} data={phys_addr:#018x} ecc={:#x}", + s.ecc[slot]); + } + } } impl< @@ -608,7 +645,7 @@ impl< C_R10K_CBARRIER if Self::R10K && sel == CACH_PI => 0, C_R10K_ILD if Self::R10K && matches!(sel, CACH_PI | CACH_PD | CACH_SD) => { let s = self.shadow(sel); - let slot = self.data_slot(s.data.len(), virt_addr); + let slot = self.data_slot(sel, s.data.len(), virt_addr); if s.data.is_empty() { 0 } else { @@ -620,17 +657,8 @@ impl< s.data[slot] } } - C_R10K_ISD if Self::R10K && matches!(sel, CACH_SI | CACH_SD) => { - let s = self.shadow(sel); - let slot = self.data_slot(s.data.len(), virt_addr); - if !s.data.is_empty() { - s.data[slot] = phys_addr; - s.ecc[slot] = unsafe { *self.ecc_in.get() }; - if l2_op_log(CACHE_LOG_HIT) { - crate::dlog!(LogModule::L2c, "shadow: -> ISD slot={slot} data={phys_addr:#018x} ecc={:#x}", - s.ecc[slot]); - } - } + C_R10K_ISD if Self::R10K => { + self.index_store_data(sel, virt_addr, phys_addr); 0 } @@ -789,12 +817,18 @@ mod tests { } } - /// Index_Store_Data / Index_Load_Data likewise. + /// Index_Store_Data / Index_Load_Data likewise, in the secondary and the + /// primary caches: a PROM's data walk round-trips. #[test] fn secondary_data_round_trips() { let c = cache(); c.cache_op(C_R10K_ISD | CACH_SD, 0x40, 0xdeadbeef); assert_eq!(c.cache_op(C_R10K_ILD | CACH_SD, 0x40, 0), 0xdeadbeef); + + c.cache_op(C_R10K_ISD | CACH_PI, 4, 0x1234); + assert_eq!(c.cache_op(C_R10K_ILD | CACH_PI, 4, 0), 0x1234); + c.cache_op(C_R10K_ISD | CACH_PD, 8, 0x5678); + assert_eq!(c.cache_op(C_R10K_ILD | CACH_PD, 8, 0), 0x5678); } /// The MRU bit is **shared between the ways of a set**: written through @@ -862,6 +896,21 @@ mod tests { assert_eq!(c.cache_op_ecc(), 0x3fe, "way 1's check bits"); } + /// The NEC layout: ten check bits, and a secondary store writes a + /// quadword whose other doubleword is zero and shares the check bits. + #[test] + fn nec_layout_stores_a_quadword_with_ten_check_bits() { + let c = cache(); + c.set_cache_ecc(0); + c.cache_op(C_R10K_ISD | CACH_SD, 8, 0xdead_beef); + c.set_cache_ecc(0xffff_fc01); + c.cache_op(C_R10K_ISD | CACH_SD, 0, 0x1111_2222_3333_4444); + assert_eq!(c.cache_op(C_R10K_ILD | CACH_SD, 0, 0), 0x1111_2222_3333_4444); + assert_eq!(c.cache_op_ecc(), 0x001, "ten check bits"); + assert_eq!(c.cache_op(C_R10K_ILD | CACH_SD, 8, 0), 0, "zero partner"); + assert_eq!(c.cache_op_ecc(), 0x001, "shared check bits"); + } + /// An untouched set reports no MRU, so an ordinary tag read is not /// contaminated by it. #[test] diff --git a/src/cpu/mips_cache_v2.rs b/src/cpu/mips_cache_v2.rs index 7140311e6..aa8dd4c3b 100644 --- a/src/cpu/mips_cache_v2.rs +++ b/src/cpu/mips_cache_v2.rs @@ -85,6 +85,62 @@ pub const C_R10K_CBARRIER: u32 = 5 << 2; pub const C_R10K_ILD: u32 = 6 << 2; pub const C_R10K_ISD: u32 = 7 << 2; +/// Facts about a CACHE operation, as one bit per 5-bit `cache_op` (target in +/// bits 1:0, operation in 4:2). `exec_cache` tests a bit of a per-model +/// constant instead of re-deriving each fact with a chain of compares on every +/// operation; the masks are computed once per model, at compile time. +const FACT_TRANSLATES: u32 = 1; +const FACT_STORES_TAG: u32 = 2; +const FACT_LOADS_TAG: u32 = 4; +const FACT_LOADS_ECC: u32 = 8; + +const fn cache_op_facts(r10k: bool, cache_op: u32) -> u32 { + let op = cache_op & 0x1C; + let sel = cache_op & 3; + // The R10000 index operations that name a cache entry rather than an + // address: they are not translated. The primary Index Load/Store Data + // operations select by virtual address, but a mapped one still takes TLB + // Refill and Invalid (VR10000 Instruction Set UM p. 15), so they are. + let primary_data = r10k + && (op == C_R10K_ILD || op == C_R10K_ISD) + && (sel == CACH_PI || sel == CACH_PD); + let index_op = r10k + && ((op == C_R10K_CBARRIER && sel == CACH_PI) + || (op == C_R10K_ILD && (sel == CACH_PI || sel == CACH_PD || sel == CACH_SD)) + || (op == C_R10K_ISD && (sel == CACH_SI || sel == CACH_SD))); + let hit_op = op == C_CDX || op == C_HINV || op == C_HWBINV || op == C_HWB || op == C_HSV; + let mut facts = 0; + if primary_data || (!index_op && hit_op) { + facts |= FACT_TRANSLATES; + } + if op == C_IST || ((index_op || primary_data) && op == C_R10K_ISD) { + facts |= FACT_STORES_TAG; + } + if op == C_ILT || (index_op && op == C_R10K_ILD) { + facts |= FACT_LOADS_TAG; + } + // Index_Load_Tag also loads CP0 ECC with the selected doubleword's check + // bits (R4000 UM A-42); the R10000 does this on Index_Load_Data. + if (r10k && op == C_R10K_ILD) || (cfg!(feature = "cache-ecc") && !r10k && op == C_ILT) { + facts |= FACT_LOADS_ECC; + } + facts +} + +/// The `cache_op` encodings that have `fact`, one bit each. +const fn cache_op_mask(r10k: bool, fact: u32) -> u32 { + let mut mask = 0u32; + let mut cache_op = 0; + while cache_op < 32 { + if cache_op_facts(r10k, cache_op) & fact != 0 { + mask |= 1 << cache_op; + } + cache_op += 1; + } + mask +} + + /// Decode a raw cache_op field (5-bit: op[4:2] | target[1:0]) to a human-readable name. /// Matches the disassembler mnemonic convention used by gas/objdump. pub fn cache_op_name(op: u32) -> &'static str { @@ -565,6 +621,13 @@ pub trait CpuModel: MipsCache { /// and `Index_Load_Data` returns into it, neither of which is true of the /// R4000 hit operations that share those encodings. const R10K_CACHE_OPS: bool = false; + /// Which CACHE encodings (bit `cache_op`) the executor translates, stores + /// TagHi:TagLo for, loads TagLo from, and loads CP0 ECC for. Derived from + /// [`Self::R10K_CACHE_OPS`]; see `cache_op_facts`. + const CACHE_OP_TRANSLATES: u32 = cache_op_mask(Self::R10K_CACHE_OPS, FACT_TRANSLATES); + const CACHE_OP_STORES_TAG: u32 = cache_op_mask(Self::R10K_CACHE_OPS, FACT_STORES_TAG); + const CACHE_OP_LOADS_TAG: u32 = cache_op_mask(Self::R10K_CACHE_OPS, FACT_LOADS_TAG); + const CACHE_OP_LOADS_ECC: u32 = cache_op_mask(Self::R10K_CACHE_OPS, FACT_LOADS_ECC); /// The part is in the R10000 family, which shares one programming model: /// FrameMask, and 44 virtual and 40 physical address bits. /// Established for the R10000. The R12000 is inferred to match: its manual's @@ -7185,3 +7248,50 @@ mod tcache_hitrate { assert_eq!(hits, probes, "every LOMEM access should be transparent"); } } + +#[cfg(test)] +mod cache_op_mask_tests { + use super::*; + + /// The per-encoding masks `exec_cache` tests must agree with the decision + /// it used to make with compares on every operation, written out here as + /// it was: for every encoding, on a model with R10000 cache operations and + /// on one without. + #[test] + fn cache_op_masks_match_the_direct_decision() { + for r10k in [false, true] { + for cache_op in 0..32u32 { + let op = cache_op & 0x1C; + let sel = cache_op & 3; + let primary_data_op = r10k + && matches!(cache_op, + x if x == (C_R10K_ILD | CACH_PI) || x == (C_R10K_ILD | CACH_PD) + || x == (C_R10K_ISD | CACH_PI) || x == (C_R10K_ISD | CACH_PD)); + let r10k_index_op = r10k + && match op { + C_R10K_CBARRIER => sel == CACH_PI, + C_R10K_ILD => matches!(sel, CACH_PI | CACH_PD | CACH_SD), + C_R10K_ISD => matches!(sel, CACH_SI | CACH_SD), + _ => false, + }; + let translates = primary_data_op + || (!r10k_index_op && matches!(op, C_CDX | C_HINV | C_HWBINV | C_HWB | C_HSV)); + let stores_tag = op == C_IST || ((r10k_index_op || primary_data_op) && op == C_R10K_ISD); + let loads_tag = op == C_ILT || (r10k_index_op && op == C_R10K_ILD); + let loads_ecc = (r10k && op == C_R10K_ILD) + || (cfg!(feature = "cache-ecc") && !r10k && op == C_ILT); + let bit = 1u32 << cache_op; + let ctx = format!("r10k={r10k} cache_op={cache_op:#04x}"); + assert_eq!(cache_op_mask(r10k, FACT_TRANSLATES) & bit != 0, translates, "translates {ctx}"); + assert_eq!(cache_op_mask(r10k, FACT_STORES_TAG) & bit != 0, stores_tag, "stores tag {ctx}"); + assert_eq!(cache_op_mask(r10k, FACT_LOADS_TAG) & bit != 0, loads_tag, "loads tag {ctx}"); + assert_eq!(cache_op_mask(r10k, FACT_LOADS_ECC) & bit != 0, loads_ecc, "loads ecc {ctx}"); + } + } + assert_eq!(::CACHE_OP_TRANSLATES, cache_op_mask(false, FACT_TRANSLATES)); + assert_eq!( + ::CACHE_OP_TRANSLATES, + cache_op_mask(true, FACT_TRANSLATES), + ); + } +} diff --git a/src/cpu/mips_exec.rs b/src/cpu/mips_exec.rs index 6f9b6548c..5b72aade4 100644 --- a/src/cpu/mips_exec.rs +++ b/src/cpu/mips_exec.rs @@ -6634,20 +6634,15 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", let cache_op = d.rt as u32; // Encoded operation: cache_sel in bits[1:0], op in bits[4:2] let op = cache_op & 0x1C; - // Determine if this is a Hit operation that needs address translation - // On an R10000 the encodings for 5/6/7 are index operations, not the - // R4000 hit operations — translating them would fault on an index that - // is not a valid virtual address. See C_R10K_ISD in mips_cache_v2. + // Hit operations need address translation; index operations use the + // address as an index. On an R10000 the encodings for 5/6/7 are index + // operations, not the R4000 hit operations: translating them would + // fault on an index that is not a valid virtual address (see + // C_R10K_ISD in mips_cache_v2). `CpuModel::CACHE_OP_*` hold that + // decision per encoding, so the choice here is one bit test. let sel = cache_op & 3; - let r10k_index_op = C::R10K_CACHE_OPS - && match op { - C_R10K_CBARRIER => sel == CACH_PI, - C_R10K_ILD => matches!(sel, CACH_PI | CACH_PD | CACH_SD), - C_R10K_ISD => matches!(sel, CACH_SI | CACH_SD), - _ => false, - }; - let needs_translation = - !r10k_index_op && matches!(op, C_CDX | C_HINV | C_HWBINV | C_HWB | C_HSV); + let bit = 1u32 << cache_op; + let needs_translation = C::CACHE_OP_TRANSLATES & bit != 0; let phys_addr = if needs_translation { // Hit operations need address translation @@ -6660,15 +6655,13 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", }; // For Index_Store_Tag, pass TagLo via phys_addr - let op = cache_op & 0x1C; // A cache tag is TagHi:TagLo, not TagLo alone. The IP28 PROM writes // the low 32 bits to $28 and the bits above to $29 — a 36-bit // secondary tag arrives as TagLo=0xffffcdfe, TagHi=0xf — so a model // that reads only TagLo sees a different tag from the one written. // Harmless for R4400/R5000, whose tags fit in 32 bits and who leave // TagHi zero: the shift-in contributes nothing there. - let stores_taglo = op == C_IST || (r10k_index_op && op == C_R10K_ISD); - let phys_addr_or_taglo = if stores_taglo { + let phys_addr_or_taglo = if C::CACHE_OP_STORES_TAG & bit != 0 { ((self.core.cp0_taghi as u64) << 32) | (self.core.cp0_taglo as u32 as u64) } else { phys_addr @@ -6729,17 +6722,17 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", } // Index_Load_Tag also loads CP0 ECC with the selected doubleword's // check bits (R4000 UM A-42); the R10000 does this on Index_Load_Data. - if (C::R10K_CACHE_OPS && op == C_R10K_ILD) - || (cfg!(feature = "cache-ecc") && !C::R10K_CACHE_OPS && op == C_ILT) { + if C::CACHE_OP_LOADS_ECC & bit != 0 { self.core.cp0_ecc = self.cache.cache_op_ecc(); self.cache.set_cache_ecc(self.core.cp0_ecc); } // For Index_Load_Tag, update CP0 TagLo from result - if op == C_ILT || (r10k_index_op && op == C_R10K_ILD) { + if C::CACHE_OP_LOADS_TAG & bit != 0 { // Split back the way it arrived. Zeroing TagHi unconditionally // threw away the top of every tag wider than 32 bits. self.core.cp0_taglo = result & 0xFFFF_FFFF; + // A primary data cache access leaves TagHi zero (a model choice). self.core.cp0_taghi = (result >> 32) as u32; } From f8383df163b4d3b089f65474191b8c38fbafe8f2 Mon Sep 17 00:00:00 2001 From: James Braid Date: Fri, 30 Oct 2026 08:45:00 +0000 Subject: [PATCH 10/11] cpu: mask the R10000's secondary-cache tags Index Store Tag stored all 64 bits of a secondary-cache tag, so a walking-1s test over the tag read back bits the R10000 defines as reserved. The manual says they return zero (R10000 UM p. 270, figure 11-31). Keep MRU, the physical tag, state, virtual index and ECC, which assembled is 0x8000_000f_ffff_cdff, and drop the rest. The mask is CpuModel::SECONDARY_TAG_MASK, all ones except on the R10000 family. MRU stays because the PROM writes it as TagHi bit 31 and reads it back. The later parts share the tag layout (the R12000 manual agrees; the R14000 is taken to match), and a PROM's tag test on the R14000 expects the reserved bits to read as zero. Until the R12000 and later models exist here, the family is just the R10000. Tests: an all-ones store on the R10000 and R10000 O2 reads back the mask, an R4400 control keeps TagLo bits 12 and 13, and the walking-1s round trip expects the reserved bits as zero. --- CHANGELOG.md | 2 ++ src/cpu/mips_cache_shadow.rs | 70 +++++++++++++++++++++++------------- src/cpu/mips_cache_v2.rs | 3 ++ 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0d8352de..fc0e504d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -217,6 +217,8 @@ hashes are given where a change is easiest to understand by reading the commit. - **Index Load Data and Index Store Data** on the R10000's primary caches keep their data (they read back zero before). The secondary cache's data slot is the address shifted right by 3 instead of 4: one slot per doubleword. +- **Secondary-cache tags** on the R10000 family read the reserved bits (TagLo 9, 12, 13 and + TagHi 30:4) as zero; the MRU bit and the other tag fields are kept. ### `IRIS_GUI_GL` works in iris-gui diff --git a/src/cpu/mips_cache_shadow.rs b/src/cpu/mips_cache_shadow.rs index 4c68e2da8..6202335de 100644 --- a/src/cpu/mips_cache_shadow.rs +++ b/src/cpu/mips_cache_shadow.rs @@ -23,7 +23,9 @@ //! to it and returns them unchanged, so a walking-1s test over tag or data //! SRAM passes without anyone having to know the hardware's field layout. //! Where the emulator *must* know the layout — to decide whether a line is -//! valid, say — that is a separate question from storing the bits. +//! valid, say — that is a separate question from storing the bits. The one +//! exception is the R10000's secondary tag, whose reserved bits read as zero +//! (`R10K_L2_TAG_MASK`). //! //! The shadow is deliberately not consulted by `read`/`write`/`fetch`. If it //! ever needs to be, this type is the wrong shape and should say so loudly @@ -90,15 +92,11 @@ const MRU_BIT: u64 = 1 << 63; /// R4400 and R5000 index differently — see `tag_slot`. const WAYS: usize = 2; -/// Bits a secondary-cache tag retains. -/// -/// All of them, now. A 36-bit mask was inferred here from the PROM's -/// walking-0s phase, which writes an all-ones TagLo and expects back -/// 0x0000000f_ffffcdfe — but that truncation comes from the tag being -/// assembled as `(TagHi << 32) | TagLo[31:0]`, not from the array dropping -/// bits. Once the executor carried TagHi properly the mask did nothing except -/// discard the MRU bit, which the PROM writes as TagHi[31] and reads back. -const L2_TAG_MASK: u64 = u64::MAX; +/// Bits an R10000 secondary-cache tag retains: MRU (bit 63), the physical tag +/// (TagHi 3:0 and TagLo 31:14), state, virtual index and ECC. TagLo bits 9, 12 +/// and 13 and TagHi 30:4 are reserved and read as zero (R10000 UM p. 270, +/// figure 11-31). Other parts keep every bit; see `CpuModel::SECONDARY_TAG_MASK`. +const R10K_L2_TAG_MASK: u64 = 0x8000_000f_ffff_cdff; /// Is the shadow cache's operation trace on, at this level of detail? /// @@ -386,6 +384,7 @@ impl< const CACHE_KIND: &'static str = "shadow"; const R10K_FAMILY: bool = Self::R10K_CACHE_OPS; const R10K_CACHE_OPS: bool = MODEL == model::R10000; + const SECONDARY_TAG_MASK: u64 = if Self::R10K_CACHE_OPS { R10K_L2_TAG_MASK } else { u64::MAX }; } impl< @@ -600,12 +599,16 @@ impl< } match op { - // Index_Store_Tag / Index_Load_Tag. Stored and returned verbatim: - // a tag test is a round trip, and round trips do not require - // knowing what the bits mean. + // Index_Store_Tag / Index_Load_Tag. Stored and returned verbatim + // unless the part sets a secondary mask: a tag test is a round trip, + // and round trips do not require knowing what the bits mean. C_IST => { let idx = self.tag_slot(sel, virt_addr); - let mask = if matches!(sel, CACH_SI | CACH_SD) { L2_TAG_MASK } else { u64::MAX }; + let mask = if matches!(sel, CACH_SI | CACH_SD) { + ::SECONDARY_TAG_MASK + } else { + u64::MAX + }; if l2_op_log(CACHE_LOG_OP) { crate::dlog!(LogModule::L2c, "shadow: -> IST va={virt_addr:#012x} idx={idx} stores {:#018x}", phys_addr & mask & !MRU_BIT); @@ -796,22 +799,23 @@ mod tests { } /// A tag test is a round trip, so the shadow must return exactly the bits - /// it was given — including any the real layout would not use. The cache + /// it was given, except the reserved ones the manual reads as zero. The cache /// model that preceded this one decoded TagLo into ptag/state/pidx fields /// and re-encoded on the way out, which silently dropped the low seven /// bits and every state code it did not recognise. A walking-1s test then /// failed on its very first bit. #[test] - fn tags_round_trip_every_bit() { + fn tags_round_trip_every_defined_bit() { let c = cache(); for bit in 0..64 { // 32 and 63 are MRU control/state, not tag storage. if bit == 32 || bit == 63 { continue; } let v = 1u64 << bit; c.cache_op(C_IST | CACH_SD, 0, v); + let kept = ::SECONDARY_TAG_MASK & v; assert_eq!( c.cache_op(C_ILT | CACH_SD, 0, 0), - v, + kept, "bit {bit} did not survive a store/load tag round trip" ); } @@ -916,18 +920,19 @@ mod tests { #[test] fn an_untouched_set_has_no_mru_bit() { let c = cache(); - c.cache_op(C_IST | CACH_SD, 0, 0xdead_beef); - assert_eq!(c.cache_op(C_ILT | CACH_SD, 0, 0), 0xdead_beef); + // Only defined tag bits (TagLo bits 9, 12 and 13 read as zero). + c.cache_op(C_IST | CACH_SD, 0, 0xdead_8cef); + assert_eq!(c.cache_op(C_ILT | CACH_SD, 0, 0), 0xdead_8cef); } /// Separate lines must not alias onto one another. #[test] fn distinct_lines_hold_distinct_tags() { let c = cache(); - c.cache_op(C_IST | CACH_SD, 0, 0x1111_1111); - c.cache_op(C_IST | CACH_SD, 128, 0x2222_2222); - assert_eq!(c.cache_op(C_ILT | CACH_SD, 0, 0), 0x1111_1111); - assert_eq!(c.cache_op(C_ILT | CACH_SD, 128, 0), 0x2222_2222); + c.cache_op(C_IST | CACH_SD, 0, 0x1111_0111); + c.cache_op(C_IST | CACH_SD, 128, 0x2222_0022); + assert_eq!(c.cache_op(C_ILT | CACH_SD, 0, 0), 0x1111_0111); + assert_eq!(c.cache_op(C_ILT | CACH_SD, 128, 0), 0x2222_0022); } /// Bit 0 of a CACHE index selects the **way**, and the two ways of a set @@ -955,14 +960,14 @@ mod tests { for set in 0..4u64 { for way in 0..2u64 { let va = set * 128 + way; - c.cache_op(C_IST | CACH_SD, va, 0x1000 + set * 16 + way); + c.cache_op(C_IST | CACH_SD, va, 0x4000 + set * 16 + way); } } for set in 0..4u64 { for way in 0..2u64 { let va = set * 128 + way; assert_eq!(c.cache_op(C_ILT | CACH_SD, va, 0), - 0x1000 + set * 16 + way, + 0x4000 + set * 16 + way, "set {set} way {way} aliased"); } } @@ -1010,6 +1015,21 @@ mod tests { assert_eq!(::NAME, "shadow", "existing IP28 snapshots"); } + /// The R10000 returns zero for the reserved bits of a secondary tag and + /// keeps MRU, tag, state, index and ECC (R10000 UM p. 270); the R4400 + /// stores the tag as written. + #[test] + fn the_r10000_masks_secondary_tags() { + fn stored>>(tag: u64) -> u64 { + let c = C::from(Arc::new(Memory::new(1)) as Arc); + c.cache_op(C_IST | CACH_SD, 0, tag); + c.cache_op(C_ILT | CACH_SD, 0, 0) + } + assert_eq!(stored::(u64::MAX), 0x8000_000f_ffff_cdff); + assert_eq!(stored::(u64::MAX), 0x8000_000f_ffff_cdff); + assert_eq!(stored::(0x3000) & 0x3000, 0x3000, "R4400 keeps TagLo bits 12 and 13"); + } + /// The O2 R10000 differs from the IP28's only in its secondary line size. #[test] fn the_o2_r10000_is_the_ip28_part_with_shorter_secondary_lines() { diff --git a/src/cpu/mips_cache_v2.rs b/src/cpu/mips_cache_v2.rs index aa8dd4c3b..6cdeb67be 100644 --- a/src/cpu/mips_cache_v2.rs +++ b/src/cpu/mips_cache_v2.rs @@ -646,6 +646,9 @@ pub trait CpuModel: MipsCache { /// to match. An uncached SC succeeding is a model choice. Loads and fetches /// still fault. const POSTS_UNCACHED_STORES: bool = Self::R10K_FAMILY; + /// Bits `Index_Store_Tag` keeps for the secondary cache: all of them, except + /// on the R10000 family, whose reserved tag bits read as zero (R10000 UM p. 270). + const SECONDARY_TAG_MASK: u64 = u64::MAX; } pub trait MipsCache: Send + Sync { From f1ad3955af66a5588c97a2769138959dcf97d7f9 Mon Sep 17 00:00:00 2001 From: James Braid Date: Fri, 30 Oct 2026 08:30:00 +0000 Subject: [PATCH 11/11] cpu: add the R12000 and R14000 as selectable models The Octane shipped with an R12000 or R14000 and the O2 with an R12000, but `cpu` took only r4400, r5000 and r10000. An Octane hinv could not show the later parts, and CP0 Config reported 1 MB of secondary cache for every R10000-family part, so a 2 MB model printed "1 Mbyte". Add r12000 and r14000. They share the R10000's programming model (44-bit virtual, 40-bit physical, the R10000 cache operations) through model::r10k_family. Config SS is now log2(secondary size / 512 KB). The Octane's R14000 is the R12000's 2 MB type with its PRId set at run time, as the Octane R10000 already does, so only two new executors are compiled. Octane r10000, r12000, r14000 (195, 360, 600 MHz by default) O2 r5000, r10000, r12000 (400 MHz; 64-byte secondary lines, because with 128 the O2 PROM panics before its banner) IP28 r10000 only iris-bench gets r12000 and r14000 cells. The bench harness names an implementation 0x0f CPU an R16000 above major revision 2, and the prebuilt guest image is refreshed for it. On the R12000 and later, Index Writeback Invalidate (D) also clears the line's primary data tag, as Index Load Tag then shows; the R10000 keeps it. The new parts also keep the upper word on a partial LWR, as the R10000 does; for the R12000 and later that is a model choice. --- CHANGELOG.md | 10 +++- HACKING.md | 5 +- HELP.md | 4 +- bench/README.md | 7 ++- bench/harness/main.c | 53 +++++++++++------ bench/prebuilt/PROVENANCE | 4 +- bench/prebuilt/irisbench.elf | Bin 308876 -> 301072 bytes cpu-tests/harness/iris.h | 7 ++- docs/o2-ip32.md | 14 +++-- docs/octane-ip30.md | 8 ++- src/bin/iris_bench.rs | 16 ++++- src/config.rs | 109 +++++++++++++++++++++++++++++------ src/cpu/jitv2/equiv_test.rs | 21 +++---- src/cpu/mips_cache_shadow.rs | 69 +++++++++++++++++++--- src/cpu/mips_cache_v2.rs | 11 +++- src/cpu/mips_exec.rs | 15 ++--- src/cpu/mips_exec_test.rs | 61 ++++++++++++++++++-- src/cpu/mips_tlb.rs | 2 +- src/ip30_machine.rs | 90 +++++++++++++++++++++++++---- src/ip32_machine.rs | 38 +++++++++++- src/machine.rs | 15 ++++- 21 files changed, 454 insertions(+), 105 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc0e504d9..d2d6e95b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -188,7 +188,7 @@ hashes are given where a change is easiest to understand by reading the commit. so TLBR reads them back as zero, as the part does; on 16 KB pages that is EntryLo bits 7:6. Translation is unchanged. The PROM's `ide` `tlb` test failed 320 compares on this. The manual documents it for the R10000; the - R12000, R14000 and R16000 do the same as a model choice. The R4400 and + R12000 and R14000 do the same as a model choice. The R4400 and R5000 still keep the whole PFN. - **TLB refill vector on the R10000** follows the address space that missed: a user address takes the XTLB vector only with UX set, xsseg with SX, and @@ -220,6 +220,14 @@ hashes are given where a change is easiest to understand by reading the commit. - **Secondary-cache tags** on the R10000 family read the reserved bits (TagLo 9, 12, 13 and TagHi 30:4) as zero; the MRU bit and the other tag fields are kept. +### R12000 and R14000 + +- `[machine] cpu` and `--cpu` take `r12000` and `r14000`. The Octane + takes the R10000, R12000 and R14000 (defaulting to 195, 360 and 600 MHz), the + O2 the R5000, R10000 and R12000 (400 MHz for the R12000), the IP28 the R10000. + CP0 Config now reports the part's own secondary-cache size, where every part + read 1 MB. + ### `IRIS_GUI_GL` works in iris-gui - The GUI's GL capture path (`IRIS_GUI_GL=1`, or `[debug] gui_gl_capture`) never diff --git a/HACKING.md b/HACKING.md index 99f6b0e58..3d89fe0fe 100644 --- a/HACKING.md +++ b/HACKING.md @@ -18,7 +18,8 @@ Other documents: IRIS emulates five SGI workstations: the Indy (IP24), the Indigo2 (IP22), the Indigo2 IMPACT (IP28), the O2 (IP32) and the Octane (IP30). The CPU is an -R4400, R5000 or R10000, chosen at runtime (the Octane takes the R10000 only). +R4400, R5000, R10000, R12000 or R14000, chosen at runtime (the IP28 takes the R10000; +the Octane the R10000, R12000 or R14000; the O2 the R5000, R10000 or R12000). Graphics is Newport (REX3), GR2 (XZ/Extreme) or IMPACT on the Indy and Indigo2, GBE on the O2 and Solid IMPACT on the Octane. It boots the real PROMs and IRIX 5.3 and 6.5 to a desktop with networking. @@ -371,7 +372,7 @@ consumer thread never takes `rec`. handler sets the PC itself, including delay slots. - The CPU model is the `CpuModel` trait (`MIPS4`, `PRID`, `FIR`, `TLB_ENTRIES`, ...), implemented by each cache model. The executor is - monomorphised over it, so all three CPUs are in every binary with no + monomorphised over it, so every CPU is in every binary with no per-model branch on the hot path. `Machine::new` picks one from `[machine] cpu`. - With `opcodefusion` (implied by `lightning`), the interpreter executes diff --git a/HELP.md b/HELP.md index 4a83f2d65..cbf59015b 100644 --- a/HELP.md +++ b/HELP.md @@ -627,7 +627,7 @@ scsi_deferred_int = true # needed by OpenBSD/NetBSD; see --no-scsi-deferr [machine] profile = "indy_ip24" # "indigo2_ip22" (--ip22), "indigo2_ip28", or "o2_ip32" (an [o2] section: docs/o2-ip32.md); --machine NAME picks any -cpu = "r4400" # "r5000" or "r10000" (--cpu); use R10000 on IP28 +cpu = "r4400" # "r5000", "r10000", "r12000" or "r14000" (--cpu); IP28: r10000, Octane: r10000/r12000/r14000, O2: r5000/r10000/r12000 # cpus = 2 # Octane only: a second processor (docs/Octane/multiprocessor.md) [graphics] @@ -796,7 +796,7 @@ Configuration --machine Machine to emulate (a [machine] profile name); `help` lists them --ip22 Same as --machine indigo2_ip22 --graphics newport, xz, extreme, solidimpact, highimpact, maximpact, v6, v8, v10, v12 - --cpu r4400 (default), r5000, or r10000 + --cpu r4400 (default), r5000, r10000, r12000 or r14000 --bank0..--bank3 RAM bank sizes (0/8/16/32/64/128; IP28: also 256/512) --clock-fixed-mhz CP0 Count frequency (IP22/IP24: 33; IP28: 97.5) diff --git a/bench/README.md b/bench/README.md index ab7380fb0..66dc6ad8d 100644 --- a/bench/README.md +++ b/bench/README.md @@ -328,6 +328,11 @@ for each cell, because a cell's features live in its binary. | `r5000-jitv2` | `jitv2` | `r5000` | | `r4400-lightning` | `lightning` | `r4400` | | `r4400-jitv2-lightning` | `jitv2,lightning` | `r4400` | +| `r10000-interp`, `r12000-interp`, `r14000-interp` | (default) | `r10000`, `r12000`, `r14000` | + +The R10000 family always runs the shadow caches, so these share the default +build. The Indy and Indigo2 (non-IP28) profiles build any part, and the +cells rely on that. Each build is copied to `bench/build/iris-` before the next one starts — the next `cargo build` overwrites `target/release/iris`, and a matrix that races @@ -397,7 +402,7 @@ device on real hardware, so results come back over serial with CP0 Count as the time base; the header says so. **On which SGI machines?** The suite identifies any MIPS CPU by name from PRId -— R4000, R4400, R4600, R4700, R5000, R8000, R10000, R12000, R14000, RM5200, +— R4000, R4400, R4600, R4700, R5000, R8000, R10000, R12000, R14000, R16000, RM5200, RM7000 — and an implementation it has no name for prints as `MIPS-imp-0xNN` rather than refusing. That is safe to do because **nothing here is CPU-specific**: the kernels are ordinary compiled MIPS III, and `golden.h` is diff --git a/bench/harness/main.c b/bench/harness/main.c index 75adb4bf3..35a243345 100644 --- a/bench/harness/main.c +++ b/bench/harness/main.c @@ -220,34 +220,52 @@ static void run_one(const struct bench *b) /* * The CPU by name, from PRId alone — so this is right on any MIPS machine, - * not only on the two the emulator models. The revision split on imp 0x04 is - * the standard one: an R4000 and an R4400 report the same implementation and - * are distinguished by major revision. + * not only on the two the emulator models. Three implementation numbers are + * shared by two parts that differ in major revision: an R4000 and an R4400 + * (imp 0x04, the R4400 from major 4), and an R14000 and an R16000 (imp 0x0f, + * the R16000 from major 3, the same split as Linux's cpu-probe.c). The table + * is searched in order, so the more specific row comes first. * * An imp we do not have a name for still runs; it just prints as "MIPS imp * 0xNN", which is more use to whoever is holding that machine than "unknown". */ +#if !defined(BENCH_HOST) +static const struct { + u32 imp; + u32 min_major; /* the row applies from this major revision up */ + const char *name; +} cpu_names[] = { + { IMP_R4400, 4, "R4400" }, + { IMP_R4000, 0, "R4000" }, + { IMP_R10000, 0, "R10000" }, + { IMP_R4300, 0, "R4300" }, + { IMP_R12000, 0, "R12000" }, + { IMP_R14000, 3, "R16000" }, + { IMP_R14000, 0, "R14000" }, + { IMP_R8000, 0, "R8000" }, + { IMP_R4600, 0, "R4600" }, + { IMP_R4700, 0, "R4700" }, + { IMP_R4650, 0, "R4650" }, + { IMP_R5000, 0, "R5000" }, + { IMP_RM7000, 0, "RM7000" }, + { IMP_RM5200, 0, "RM5200" }, +}; +#endif + static const char *cpu_name(void) { #if defined(BENCH_HOST) return "host"; #else static char other[20]; + unsigned row; - switch (PRID_IMP(cpu_prid)) { - case IMP_R4000: return PRID_REV_MAJOR(cpu_prid) >= 4 ? "R4400" : "R4000"; - case IMP_R10000: return "R10000"; - case IMP_R4300: return "R4300"; - case IMP_R12000: return "R12000"; - case IMP_R14000: return "R14000"; - case IMP_R8000: return "R8000"; - case IMP_R4600: return "R4600"; - case IMP_R4700: return "R4700"; - case IMP_R4650: return "R4650"; - case IMP_R5000: return "R5000"; - case IMP_RM7000: return "RM7000"; - case IMP_RM5200: return "RM5200"; - default: { + for (row = 0; row < sizeof cpu_names / sizeof cpu_names[0]; row++) { + if (cpu_names[row].imp == PRID_IMP(cpu_prid) && + PRID_REV_MAJOR(cpu_prid) >= cpu_names[row].min_major) + return cpu_names[row].name; + } + { /* No snprintf here — freestanding. Build "MIPS-imp-0xNN" by hand. * * No spaces, deliberately: this string is emitted as the value of @@ -265,7 +283,6 @@ static const char *cpu_name(void) other[i] = 0; return other; } - } #endif } diff --git a/bench/prebuilt/PROVENANCE b/bench/prebuilt/PROVENANCE index 235efddb8..2bc03f259 100644 --- a/bench/prebuilt/PROVENANCE +++ b/bench/prebuilt/PROVENANCE @@ -4,6 +4,6 @@ # CI compares it and fails if the image was not refreshed alongside a # source change. The ELF's own hash is informational only — two correct # builds of identical source differ, because -g records the build path. -sources sha256 b2aa6db09ad6f42b68754e4199c66e0802e8cbc9f3c886e6a2c92b1f3502bf67 -image sha256 21dc4eade5b3326afcf77199b405767a56775168c0682e65c9ba5134253b857a 308876 bytes +sources sha256 c6e4d35f0e4850bf91c09d8cc5f7d1aafd56cf631a395e551730b99eaf78b0f0 +image sha256 6b5e381142d18709dbb91b708ee26b1f1e6c9deb9b29888d2492deaaa8989a71 301072 bytes inputs 32 files diff --git a/bench/prebuilt/irisbench.elf b/bench/prebuilt/irisbench.elf index 12916e07b670125d400fc1ac65a31849c437f316..fc488dbc0792df81a1af746de0669ad85efea807 100755 GIT binary patch literal 301072 zcmeFadwf*&o&WznXC}!60!%`HiBg?mX2Kvrh8i^5`MSp>3<0$UMVDT7Hzh%1(QUfz z?xx@EIN*-8@AdyZMCANoZs{P znHdPERrm7y{d10nGv|Enuh0ATd4DeFh9#GzE!&dgmn{K)TYX{krcwM~aQGRKMhS~8 z38|544d*}6IE8ozJH%Jl!TSn*-}T97R`C1Ht_ofT-z>m;=ON%B;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424;3424 z;3424;3424;3424;3424;3424@c%CY{%Wzb2EM~iJXP5jj?a^TRoNb`c4U^mPfh0C zTJBYS(RhDdhxO6!$gTH^4F9!Ad|3R1`Da|`zCJPTcm7u7J3WN2l^|i`6T*6}4hfj& zK%*=U$YH0iLm$oMWV(y@0dX>$B^Gd9r*9R%+symad-|etzf;#S_dD)kUp604&F+iL z{nCfqQ-QunJaDjs`bXpQ>N=_`#jgp5`3s6W9uJ6rYTzuBInS=itoTpL?u+y{KM@W( zQmL;}_V=9r776w@ORe}qDgG`LJDBnvrrs^VxVcL({ub#%q?`Sx(m8gaEm~F~Fa4$E zQjaB1G?;t(iKMx=Jdu#Hrj%4PT`1+@l-wLP<&L)=97zSfmlfZfX7QcB?$#;^B{xV# z@`zN#0`zD32W%<3oWEsu?1)swHt^Sca3r~1rb%Dezi2J@=Nx}>k4#&%T--(TWLokX z2@fsduSEhwmq^vn#S$D!OYP8d2@Nfi*+Z=o8)}n=+QVYU$|THRFxf?%C6cJkoOqY= zi!EK@Si?XAg_p;g!;x!F9lH$+duS*=_N-`en zlw4}^pXFloCw;g#Hc71hYY5pbR&573SH$e(`mhXTr8U?gHQZN<|1_I2&J_Rq){))< z6N~=HkV8hE3i;)haBOI+v<_{PmHkV_>2IaHr zlqI3~trhN3Xy@tV)2@4Jzv=Uk^F)*BM<4xo%@a+g|Jn}jj2(gA%92rerYR!NHpL_p zjLXyEh~-btUzwBgl)o=x;x-@r`cT&sO(yT9!3Z>-k8SwTfMk<#_j?kU8Yufa#YN*! z4V3RAY(&eWj?-eco0n~gh-^v3WL-EG+$d8`IfVb)mBeY5VC@$7k14HN=MyooD%Z4n z{o6khzJc&{?jQBJ)V8_P4gtsqJ48`ZHPuUq-8IFTNWvYVTOG6Ra9g6g?G4-{iFEk%|l-dsWRdDmuH-&tg zPrrkF2W53A+R#Ow8EMe`$fru656uf+%gB>WQ3{a$H2Fb)@+AGz9iBgQCwXSv*G|cE zkUalwLY}jVc}_l&r)Bc|Q~AZpY?&I6e9BK9%x`P9{^pu?h<0nA&i#%AC(zD5rMV&J zV0Wp%i!^xR8Cr?0KG;3f!Ji|3{-AN>f+N9kM?(CC`AhJZV!`)i(P)ZbGB z{@$V0Ps9p%Jio2hkuRizeUW?Ri7*(i)-pBTe-)dl0qeacFMnS$RbgdfPrBpqq3YX6 zYSNkRaM!`FFJ6x9SQn0@Dz|T!&n9E3s;n%Ym!Bd(PR55mBc{)_js3gObIXte0V#{4 zGphxftY~V!l{`$o#L;{-4^6AIqUkl=%4P0LnkHo+#hGogxh;k@-&lYV>Ot z`W3y(--Y5wx2+4uo$?d9aYt5U(-y^A&S>o1kbx#l-4rvuGz?y{c5v6<8eZ$TuW6X$ zJCTpk=SzzEyeyHDvV_s+vLqM}wz~f=t%-#yD~{`IUv)2eEu>x}g?n`q_XRvFUGhHC zE9;Jj^S-86mY{F4)=Q@S;8AKfJeQtmlY@a#q>pMu`jgG{oz7iw9*&iJ}9e$^OIY| z6&oOICnAB_qIwLw#SP}<9LwiKlIz7sJKqbR`(rh@50KDJ4f{2)AETACtOI26bJ4eI-$=S2AP z^A`wa+@sv9Od8^nrc$mZjb1Hn5jh-+Q=VV*A@1wL3EmS9F6H17k#sVWT~p8pE3bBs z>F<(kq}@NK4MEu$s#n_xyXMcd&9wIdY&suhm5F28mTq`Jf~eg|u|BDmt>MT(A9<>M z(-Br%$;v+Gy0yFASCY?RV`-edP4jCHOI>UOc@V!Jp4WE9x@gxg`Ms?v(y#Z{aD=u6 zR3^w>#du3iysAPx^y9TcLEsahuEf{8gNNN;X&TK>9%!1s^03q#$7O3V?-u$o13nuH zaY*y(a3$q{4{Zww@k&_mmJ2#E*ul$$8T{@{LY%7S5zzTW7}pP}-RE4ByvDJzZ#o()9?x_Fs}K6qdIp!<53 z=ThA!1?(p^4S7tFo09N~_y^YUd{bfEpuY#Uk|%a#umwH8T`ZHfC1~iekWX>k(1t#m z#F%Ay?r{k$w3A|ya~zUceI z?pGyGN#OkX^+fxzrQ+{g^cpo{!N^+DJ@8H{9Fjg9oWT@yS@^$_wjL|=wA zzvJ-;L(Y%udksHC8OYlJddBn>GS|eX{48ZVl)K9PnzU1wHtNwt|6L)uzPQTR;4WkX zvX4Js?JjHvMlLbi_gpY5m&iJK517#nY75F=@r*DE*GO6Le>2)xP?GsjKuxOh_vfsc zcg{Idc}Y|8j%}WdFP`_~hh>?(r=d+INiGxDafJ_BHu?HOuZb@_BJ0Bo#2@Y@Pt`f9 z(~{XOs>7k*j$qub*Y--~+%5Fc3TV?$_%`|t`dYaaS;Fu7dhiQp;!?eNzJ2xPi2QzY z^t2ACfFk4dmy?c5@l(uZUg7>x-}!b9L}JrjSKqG#_she`_Mq$5B++GD`g`Vd_h|j) zt_#kq4uK(9w}G_-)@Gan)*ZE3_umu~u(M*nb=}~TT5cw;eLAt+tEwrNcW;&#^;$5A zdT4&ddY)aMBrkCv*Yag!LBE1qjpk{t)!HAy8sdCe@#p?I>d*yU%~D%NZGZH%+6=Rx zfk4ALzwjGRKsd!%D#ran>Jm`?fG-@%-$(huLfD+|P6%r%g=x7OU!O^%QeGHW+L|W0 zVVdGp$}d?;!?+~Uzw7xy`fv)ijFl?;-gg>1Z~C(GcjNZW$zTWL5cqQd8wQ>3M=!q~ z>vUaYzf0fxeejeP)8G93HtMhA5n~_d`yuk>eb(@U(zCcPX5R^8Ry*qc;l|GU zhgD9fy{mj}@>u=+HjS_O7R#_T%}{G$+@N846~nb1I75v6a-tm@OgqX`wzWv*;KX+5 zyIAuA=o*>oxW_cFQr#xxt8FWlTSYsL`)EviDbLik<@v#4J+j)rMY$3ntxq!0zjIVI zi$DjHYHZ}DAI!1;p{Z3iW4`_;4TfdfPw%A=)6RDB>+=NpVR&BCXxc&=_eG5x^T`za zBdS}T*K+ilSP!j3W&>22kqXUI!x2*^D1j7ipgi{s2Kd0*mvb7@BRJ}b)?g4h`kL6G5ysUEuu*%Fu?yjM)y>H*e&kBl{hc`B_&R?QWr~5~J zHg%(1r8ne3!4C(I85+~_pfT+e(yh|_3BGZEr)i6Hl2kf5H7`x>&xlXcOi~%drTjaQ zh9=T7`7bDzv*1KIV(7P6&Vph&SU=%~O2eA3$}#fn0Y9auHurw?;5Ven{kkNfs|0iv zhSoyvc68&N(&64E-R_|DxOYph`xVK!_eh@WDX z1fRZny=PM1S03mOL9*vQjf#=Rfo z-o^cP?tjbu=2UH8eO=eKvJf$sz8?O89@N*iYIwMf|TWwU>ObGw^+^a4&nOG~DjES84i* z^`*QOC9I10T&Cr#TzGq)aF-%u+9u|w&+mlp-=fZMCT~i7XJn1BkEVwgQtznNTj})w z13C;)maX_`dHVZcYk}q`^o{CRQ=fxZ6vE)GGVM2wV>3n$%CSFa+W&gnk3C(gPf2zQ z@=|R>wGSU}*Sp#s`o8e);Sl#Mw0MKIMX%WD(8Fnc;kh3?{oi~=xyU>FP2TxV zeaCZT?gyXW>0ZS63jTLnu+1!FS>#}M{~UvXHN<`BeNyGv9l~$Fn?5KqU2QY2Qrn7QT^csa5&Yb!gE>9YPo2bf<}P%FU*C1n9t<(N z_}lMn=_%&>{LVwP_YmQSXs;%p_}9!JLDLkm*>{L?oNxE&D|3}Fdnb8l0_OrpQm6Mt zHvPl%hvl??|KD=jzFyyl_AQXpemZjA2jxuX+d;YJgW@>fHpQAUsDrV^^r2KA6Tm;v z%i&mAka2|3%^|h<@W+m#s{_UNVSN^-54yomMO^F_r|=FMtLlr~x;`HOr^%_Q?%$=R z@Vqr&8~nJeqv`R*kNoi(nfl45HIJ;hfqO3i1r|T@-4{=NukSRzrcYJcE7#2Xt7VK| zN7l@{;(*>4&wJuMvB}UTmIZlKGWTX{8?Xf~v!mgN&Pir(hQ{z8w0BFBjwfVl^a8mp zTrd8!du5~E|L!%pt*734NXKeTHR_KG-Xb%k;;aj5KkNQlDt29PPDswQe0!sm0iA^7 zSH#fyn%B*VnbMVv=$xfppNufx{fK0Gd#1Va0BP}UsgF!@y>WR4f1F{>u@4&$MG-S1+m2v5zRNa-u+RQ z=h{BX!LHQ$4E5xpb?&S4Rg5pJ;rsHn!|U<^!|dhc1uF|SG6 zspFqv&r(P6?`pdHuiJa$lCPtN9TU$#k}O2;<4SZcPAJ$PO z?F9DWyQE8frhs?aXQZBakIENo-u z1gtC1a-Y^RtMTd6?tom!oY5A1dEJgbJ4juL?=v*7;b+6vwO9_x;mSym6xG2=2v)E{@%j+4`gH4>S(-ckM%X>O}RN# zu;0O-ac;d_EwiaVK8IjU?MD2!gsaTx@1&14Kk|vKu|(4wY*pT@Lq^|J@T1{Nd|ltG zZ%6yX@`dIzma{FPj?7mvrx=9y1KOWbaY0Jyqw9$EHJ|DNF6{?RCu@@PO};l5@~zFe zuWB4kTfoQYY@-L!c_P?NE;2>s5i;gA^kJX|eWPPdk-hO$HMaheJYj**ZLxgq-1Ehn zS?7-HJC#LfCo_jwl0PbY#GX;|Pll0uI~8-rzKQ;oFNpE0d{^2eyE*QDlX3C=jEld) zxEP;^>SEQyb|x6F-{=T)(Jtcyb17Y}+=86qxzLx-kAoF+%*c)~>w==8h^`wj@m3R$ z->DheR+S??@mP&z*MHL;ufN~@W9$q!BeyYU#dZ5-{I!U6`x5l)wEvwEU!7w;)mv{p z(_6pjMfBIS-i*DeH*#xUWYL2+u$Cl|!MM29ht9J0bw}e{UALk01{Zsv&z82heebI1 zf=)~4$gJ38%eIwYsw6DZM?G>nui!U2=|`dYq^b0khvv&ep@@}cu4O%QAf5Cjva9_X z%cL!in4p)s^9TSm+ZU{Nt|3;G5KVdr#C4 zo%IWg`e_^uBhLlHzoG5mWUod?gMsR9)$itAC%$gxICZWp{s?@z8~fmIl_u#yu(S4? zdR4>k5qmX0?=K(=h|5^rRyx$YwybfF4XnZMxZZu0-!A<%tr6d<{BsieNveEc0bQ zj?8#WPK!TC8}?H6#-<2;P-cZ3)BiF2_`&3WyY zsWQs;74*bg$tMlhbQ5JrQC5Xbd(-(^bH6wrlw5mUb&%odDd@T?wbA8<*feCH^7B&Y z{x`^8^Vn85bI{jf|6PWzIt+hx z^u(@wKW_+yjJKNy>#75z)2~cz+rKGJNIc{lmE^b7$UQ7;P(#f@&AWA*eV`HyI`l8 z55-S_O^yCT-|094DY_Rsds3UmBY!FCy4OuuNzaiM{no4H7X7?t9wZg~-T1jd?1& z$yb@Xv0Z$Zq{=+s$=Cy>JXeQj$^f>-M)K;^c9GZBtP$qD$)h)n9$jibWNOg4uWOiM06D}bj4kN4lkBVy>$Ay!S-w`+o5p-vFSS8u z?9_3rhT|}f=v|f;^zT4xf&Qh7zFy8+<*mqZ-zwG#wWnnAstaXO`-L(&+9Z>vH?ekf zfh=e4*B@yTn{`3AFt4zjd0YP+o@*wAhmX>KM^A(wk6%n5Jtp?_W8!D|j(r8RxhiTk zw?}322hgG`M1GKr7J&8Ws>;7KHYsyo@n!oBDXwT3ccA2ih(0p{h zQG93FDwh~5)$5!Cd1kCRj9H)?X!sRb6RJOsk7C34;N4)O<-99=-pJpVnEGF=blCwe ztOL=puDKW!D{rcuRykv*)m`*YTw81(a#LlX`Uv2makGxNteY_b>!+r4>)N>sWy(2C z;y=Af9!@TRRu*74G+{^T^Fp2%((gQ zQCW|C^aJ^nYsIR>cEJv@?u1S!u@36aM3la)U>$YTYHN!wh(ezo&?oIN^r>yCK=eG* z6xVU<%qn-6EDhExT^+aI!EA!v4mR-mp9qHz_kkNy7aTLJ=kOalM(4IdYQr1926LSn z=Z$s@el+N*WV6(SWioz?apX;0ec3wpxNQx(o=feS+n_uAz1GYm;||_auY^<=#~r84 zr%q@?QqvoLp>4-`26=C2q2&cX#sD%Pq| z&ayVcKjI)C%UpM0HsUvykgSsB*Mo3+t1>fxioM7_17y`Fs?*38MQPnpy{ z_fPeamiMQ_4LZNK8cXvbJs=Xx6}GmLGmsFc-?*w?m2?64EJ@p*K0F1e<$`HA<4Z~g_y z{(31p1KDZr$Ug2{&_iXXU!a(X@7!KvkNd8AO+Ff`M?M9x!|1bQ4Lo*X>rMP*T}nC= z_;NZNL^35NbIudNA zUju1k*FNRG`cen$#+C*IHVrS4O)Bew3_v97w<{khf!Iy!Bl>@;!{ z8f&b`P@u}v)7Y2N6fydw6PqF+&cV-U4U%zrC^1uQJJ}MfmlpI2bufBmFM5SAWOiWX z)9%X}{}}a$RuWS4R(w@^v}p4fzM2%M%4*wn9OKKP>#--G7v@*0vMwRy6*{y9@l~*s z)DMtDF0if@6TttztkMqgn;8Em8UH8n59pkD0D2=2{PFlBG)~O#GxR6UVEo)-x&r-W z4gG1j`bG7f`YQ0D4rsbUoSpI8qWLi6MZeAg^{>x22LD!8Ds7s-GVVorgMZnqMIZh0 zSYqf4`Nn%cnNQw(RX&05HfCp&aho>cL#Lf(3u2XXKPg%C=^$nM8N*_`h>ubCNA(WR zn&;Ae?rx(+d6(3&Z&x@PTc45E_0R@$C~53*=)$gTbASDk16>@EHPGjCvF*M@{YGC{ zeIescA+GvA^f#gfn~FN*Sf7?D(pv}gc2R-eOukBMTiw?Tt!*IBo86aUdwdD>x20{- zd9kUisf_J;Uly5~M8+n}bGa|9I{)4|`7nLh#F#wEm^{IlJbZ}0d6O}k)4wL)P`lF| zPAQ&XI|O!mNB6v__-T#NPYcyXRoOf0jG1*Cqb*}*pU!C8m}A~A9b+z)@bp-FYc?q9 zu$@jPtY%H04ohn~QfGXX>A49>M=d8EPNvfFKudZ~II{$9NY4pm(&4u9mFwM?G#xS^ z)0)-Pnm+hmy)VIgrtL#-7uG-fgCk0#W=)|+K<~X-*juHcU6+>H^}t1Ay;}bVnhzR3 z;{z=R&A9ae=b-V~KXB=o(FqS+a&WeZck#i(^OA#RzrzE|4>IN=ed|H95AA`rgN^2S z*}-Jm!cOB#Ss$Q3#T(?W@lC&>yQQGExSu&F@Yx;hAO69sVeVnec)}>KFnua#d zPFqPQT`7fUV=1U%r1vk$v3MqLD$A<9;8d$=FcZ%$OwI3e@By{ z_uI}P&nxqWhDTe+cItdiYc?cywl^-*2cq?V&Db%!7yFv^y=K2Fz7^(c@Dp{)a z$A!)>(6x;uhG(S1iR)fI{k`&9_t%=IrSm@lBfoPy5(pFg6RN+-yFlxlew@wTInD;`3bhwn{LvrBgAucZ<~@kLld9>fU5LJ{S2K zkj`75qGG;aPRB{XtHnRsjQnOj`Ad$-OY5*zqQ~XcWVH$HHPj7VF!~YV5htd)16raD z1-s%&>ejNgu+Ls;jIjoS9UfkK}IB_8*M>~4p(?@hgmeXI(d#5J15hJnwa zMISWz-d3bGa^tj@c#qx7T5PUc!u3`dor9j!dbDl}nYyGSp=Pbm@wzP0cDP4Jv+mLT z*7&~IcIp)v-=}%&+Wz?R@yCysft=7X%wB+EyxJeT2Q^MB@ApUWA+aYq9Wi#>IC-dT z@s9n))l<+r)g8H)sBbzPZh1N99<`tk)uGxXgC%3v0-o^K&55(H?O)USOJHZtzG@^I zf6$k(zqm6}|B5e3e*V$bzJ#{zr4C=>r7aWs%BTJ^;y#6MBU>zEIeSlkoQxQI(4n1_ zW%>=g{gyy}UahpoeH6LU0w3=yjkVy{;uven1+T!zjGv|o zW2e?EfEBN)fvKDIXS%USzmT+%xx(B^VJ!8EiCW#4lIp$-8BdL{SBU*ob-M4Wu-~fi z+zZ~J;yV)uA5h>B^5ikf7CTt-g&Dh$dKUc?Q!dc_OZ8A2R&4_Hk@R=xlWMyj_W`IK zi*F=e=?hQvi#$=LInYlVLo>~I=#+W3l{aI@5~eovl?nG{jZa;V`${x5o``uy=C_XR zOHD(Lh4`!EZ)!oN?LTtBd2HU;;r)BY@}o<}_C6LEdt7B^YZhCT`XU$KxNcL|b$+w3 zu2XSO%^)vqPhD%SYv;_G4z(-Q9%8*nVNW4x_YeX(FJ4ArNgI} zr^BH%{ZpkjjIPyAHv}`tfE&{bg6p6cC*6QviUyqY0`y9x=KJY6lWt5md@z@e^0(ka zcDmtm;GcOBGt~~6%pm{!e%UE*%SH?zy zq86^*t$3%yAG|3Yp0ua9-h4bAZcm%>FZ$!rkBsF;Ul=<&dg%c%ee(VTYCrsirc--Q zFWQfP4B6w8e}2p!dpsRU7G$@m{M;EI{mEF{{#|4F^g_h}yF%ky%I=U$5MJh(0 z95Z$Za>F6d3GrN4aZk;nJ}(~#rsq_l?{OsaJo@{wqx-))Hj>73HM-+KqVtYIDFG9+o3;1i&*0q>4)mlW?H8$xO3x?Hv-nfGr;nh0H!_H0Vg~1k0e^OsXdW*EkT+l2d-)~|JOq{}4S<8@F z-y63d8vz3M2IP#nPRP}1k2BT|yul}+K1`LP%rUgqYZBHgsE=9a1S-Ulndb~!(lre z^Kmz0H`$P$qvJj379i{PJ0J&21!@r4sX@wFe>K9pair?ML zm9T!}8t@>@jAsh)qetvBRGx!NVa&1Yz-HFACX2dduerC3J#Owx#}1qO@&m>`2L0*! zO#Fo2(c|rAePQ7peQCnX{0?ypX52%?_p^;ID#S74Nqi(7s+))t)-~)#$Kc;EdX0FD zm2Vo|K9+aCD}B&U2KwqnkM&^lcVpkL+Ob_4_TM>}cPC0emxUJGM&G zj&0JYelerFbZw&gE>&-;zGSZ9xDHc2r+QEI=}i8RRYw1z+frwky2VC^4rI~|ld&f| zQmu13kki(kx~4;%P<;Q;fu`22-3HzCf{udBXZhRc@PSP0mX5;v2Ilywi5a=qIM| zu!HtI7S=xQ&}?}I`!HC{5qWGXad^MqL5H2)x$e=&&|!-Yta|kK1s%5kc68XoV@;%) zl0N$%ZfvzXNZ(_p&r^Jn6^o1abBcFHb>{t|;(bBk?su%RG{1w61RlL)Y(#xKS{KGP zRxRr!p%?U!*ct|HW3QBG*Q!j1GxS-a&`xF&RW@$g3a{Np-L4L*dO*M2Mw?`Ov znDwHBA61&wI7@5^V7oP$_zg;TCG1%Lhu+k%$ASkEqaP#9*_{{hCy%~g>$A3{bzO(C ztwfMlU~LWKBBRUwSq&XTo#1^xNDQ-jYiv z|6v#SW(=P-td++e9_vXn@<81cB4PWt|;+rsU5o30R03F`Osw(=(2+* zXKK<7oz0I{9ms9kDTznVJFrjN`)J*Py*vk$*B+g5;BkIeJv#lsVeY~7`JL9IH3y#K zcSz~-(dq+ve$Re1c;G1a+VpwgGi|I}!_te3{CrN4pWj=2{uBIu60K_{XyY(Ol_Ib>kcxmE%vSIv$MewJ74|(SAOEy zeJTrB8`X!MlflmE#ShzqAGRAmYzKbWRgA&f8H=?Qb?t!COY5Al^39%CwqXZmu^opr zPbtb*cVU5#G$!xECHdk;PvJYlI_MWDSX};v{#9=I=Z;HjroMIOaT#o6pvkK!U)bZ} z;!CYB%AL)}Y27~dw8~s$QqySvfh?GsekcCHlk*SNt6nI{)rr`?t$dYZcjJ4nFV&U2 z@03>7L2#w#6?smMWz6$}50%RQv_7-(%FOJ#~Jw`lIj6PRpbq-V3qUMx;Hs02-1a4Viu0 zF1Fm%K=nsse*2B~)PJ*`sW#64q~AQoifiM;p6EB8hCddYQ7*l_{;`u-6H#d0d zxNxH1T=9Hoe)9z5`FHO(S3HY;^ONv|BTvE;emV(H!VRA94#$IO<7X!?F2%DyogXpx zRrw)vzbrp!?(ffUV?2=4dC=IDOK!o|K6yTq`7-S7<7aR*R%O`hFuE@`=^oCUl1!}f zj(x0)qSskR^E1{2?&JOdYgsw-Pim?;6atxJS3BGz;_u6e|8B8keR|GF&VV;S>0tnZLA`QLk%45ntIr#CkA{H+Qx#wq2|( zESuV5TCurCuAr_fsP|ItcCC+fu@7a}nX&pinoBgeF3*46+?VCEsmbDtueFZFms-cH zi&sUguw(2oU5}}23w6Eam*FG!s+hHetZ~#eO^&1~e~H#1xL$2HtpjuKX5Z4lllXg& z*sQ0t<;%9^);{mP5NCCpDf5#2m*Vpo(1zJ3kzt=iD>Q_Srg_X@4~w3AlbS*|Okz(3 zX>?9_@$fhk0<6dBOGM|OK>(n}-PFtwcTGow#p{Wn~X`O0+ zjel*e&HfAO#BK_cH*@?}tj(N}qjia~UYRwRApUBaw{Uz+=L1+h8 zbuIH0vN5cCI?84&U{0DgihrKZk1d51izl{Px;9;X)vlgJg>TpTGFZ;2bD!1quUf9w zL(A1LeK%vOJN9Ml;`$)?f!oX)_ovLqSZ^_39oF=kPSYbdf23)pd{s`$+cVbHoL}`r z=(n;hBcEwwUA|-Z&0?NL%9-mAI2mcvgChN(VnYG8->tXsw~Xga{LyCXQ%=-3 zm3=Pl;i&b?WYqc;^#9A=h;M371ic-xev*&M#kr{U6P_>Tc~>udJ?QLU)MEI5+K9tg zKe%Iu)Y^w-y39!AHmN_UVlcOZIsHxFkXotuCs_RZvg2zK+o55zHaosqxhTG}8vA8r zNT6NQ1f{$!XSKCQta>onH4r6zi1kM~skocnA{w?cN?3HqS7o;S@ym=MGMiYVV4inKl5+JNfhL*pEgBW9;kiLp2BYMkl6^Z0_B1;(i*|%^8Olofrqh0VFhf{u(-!<%6}=hj2-qUqHr*vvybqCg6=4nH z@5qU-n^TQ8M|n=_z9(yIH~sJ#PBtTKN_UQTQQk!hjGQsxs7$vyS4C}KCSqOE9f*)_L|l+AOfTSU|PF5DYEo@Xn0?(T_dePv@JN>rHMCiDosLxB!i?T}ANtgxOzlr+=%?`3cL$^Q z=Aq^1LJ{%^Xq!!2w;(rav$S%vBmLk?9j&Fv?dze3ZZP@}bnOVV1sz&n>yB8T1BYKW zp=*D{PQKkfsdyh&>U2)IS?iNQ`l71Sckinr_aZrmkFck5HGjkW^`lRbGmHxd7#H?2 zF3d14>_y)7974`8F6_XjU#0dTKG-ac!Y*3DUt3N-y9(LGtk|`bjgGXCLCQPo*R-0c z|FWdYus8Y*8FM1TRw2XMkzsB9yUFvRWTby@@xG@Zvu;({bsKW*dj6IZ7Erl5lC!!g z*AD0GXGbE|!|cyEoQYe`-njKJeRMbZd9yAY-SHLl5Aw{%`ocq$5tifzs>me}N`1-AH!aLe_Z8!C?<~BtrGf7-O7$uc&OuNd#o_v+xRPOQK0pFbUm-&d1 z+u`=ObvM4@`>225`x*Nt_Vo`-f-=Mx$VGXd(E73NQ+X$&?~MFf(-)P{JY+&n>mM`t zpgZil2O~T;i2ad_*qa^up`H5dx7Kw;&7L&m4!o#x&`}v%dT%cqP&{&$(-x=RD#M}@ z=ylKw4wyhMdsXK(N!3T-arEsRXao8reMIG~y&64&{;~xRjch_cslKC(fUvF`*%Yz6H%D3D%N`l(g3XPb3K&_wG8-i? z>d(TNv)ZG^j#v3Y|5^jo2OdWLBxKSRKHnnF6f4g~?9XpTw|iMk4IFSB$_lm$83{jQrtFZAX~(#!Rm8{M%A?=y zs!dz%+3XLF5EkHfP*w+-x3M{!)%GJD@desJ8(C-{Zi-9Gpze#rZXt~INxEK0*Yj$; z80$>ra5%1eaboNvFWA*?rgn+@`p|m(!mRCOOb}+>&&x3!$UbCR{qJeVcWki_55zZZ z=gzzX<6+JPnz5R_N1WAS3+tD{()(#?5xoC$wYbZucckLq7y!d)O_-`L#Clri?LO z0IRU(Mt@^B+O_x=BmDN`OT2++r3bzdKnWo-Zl-E#9B+N53CVP0|MKjibK<=yJ2)S|k^5 zoR*RJt(=QCS?tBjGtwB$iA=l1CzZ<`pEz-|*1V$DC(DB9@T4QVk`e1BwINn^I_4kZU24wz8Ifi zpq&z{w0dN9E+U`W8;MO~593tE)j`gttn7$N)oRCAh3pMGabH6RGI~`!zEGyIzHgcZ zKU(+DzD$uGwz$8gcgm~^+Q9`aSi!WE>2KpB=(Lmm-l^ZylX zgdX(WjK6k&84rY5)8^){OuC1(9@uMdIRDVJ@6!B+llt-E{HM+H@_Z&Wl`~<=#fM!J zXYZ@-cjR|*|7(~%s7D;e90fmwwZ7v8(aJFlMfO#67~;-KVssX-$1D&VQ1A*vELcu#W!}zgPTvzu)Qz#loCrTbVjSpAT{k8%D1`(TAVTk*AlfRzo#??C=(I?Y4< zG22>Re=WZBm{^BHabJ}a*#Ix%-%)k*{H|)ZFf4-xn*XBR<9@K6^!9MD`K(PvMC2%{KDecC}x&b@}aWtNngxeZTr2 zV!yIw#{1oebpHo-{GVE9pQM%ryjt?t39>ELO~t`=sDOumWn1wa7jztZ^}f!YBcJ*( z1R5UL1txpI16yBp5Z~S?obT}vXSwiO^HCXYzH`7?3+zYuqxv_DF9w~V=MfiauUq3; zMLF58v_Zb`uwV6@_#i9g@ukT9!^nM=q1$8$pQ_FE)o;`g;j7A%+FuF&&l!C;f_`E1(@t@pCt5xaIfzPz)LQ{Nad^5*ts zBAOcwT=lwG!)d%fJ9h|W68eT6eCA}TwPoB8^0SVA6t>zVemDC0>jgSzRr zXe=w2kJsMf9>Oo=H+AV~k7G9r_NbpUReBE3j32pswT;kdaQhOG?SCn@AR}f>cfW}o z&~?rHqWALUH&OZ?=t8y6|sSI6$uh}XKMXc56 zB&DSR=nE5k0G{I<<;>jk-Aw%=@~h6_j|e%;dpYtc{MhuX`q3oxDMx(3j9=Y1jdxw} ztiJd4W+Ygb(|Fday%F|B_JdhBC65G?($rSy*74Q8@}m8I_^z z(ejCZmrwOvqTQ0jr!1LYZHYf4e(mp?FtQ36ehz=xpNRM!eIM4nUngvg2gLGs==)%N zy2b~VFp*5ya|2FMp#6SgWfjkC>O{HtXt z-@?C>X`dcx?7a27H7|0;8E5OHW}WqwRNd#6rE2bxdg5|;Cw)7}-oR;7 zM6&U7U-`;C*PI{wd~Eue+v+dx_~yBb9$mKhMb1YHT35x+uriEW13SI~-DW!C_BSO| zzs_ZRvT%3(E%Ft{?_%e$t)*Rg@+v!<<#%@wpV4}2dv{ctRX*futS)G%%VEw$$EG`W z%cS?VSlKqEF+Fqq&(x138;FY?h%Fm6??)1m#Ne6RsyWI*``cavPhzV`+0xzUzZ#VW7ew{?rs%(qOgV<0DG<+~9GrrQS_Hkhkr0#R%{I=2_NZt4NG3Nfh z;9h(7H{=$8uHh{BikVqi7B53iX+Cl4y(AIw=hPl)izjwrpE}S;B{cF7H1bOf7xRBI zKF=dqS+Uro;7TR5U5@_&orV7u8-V9!w0Fiusn@1)8_?+&5$m-+i!=7fPpJVcq7P$O)gF8I0qr73_8F7RDfVur~Bx z-P`LQEmuE6mHHo8BjHzBFvMICv~CUGoF8E?*-oV?|mTpIqq)7?(!@e zfqHUQ#|xaLuX78hDK^;W--avc>%xB6B7gYc53~QZWGfeWLHBa7?=@$5L7cwgKG@Rp zW}eOYf|VLyILmEn;IuD^!#Z)kEpzMYyhGpk3;Xu-?R-$;QreU-a&M{HK?VCK_KZz! zka15kx3Y!f3hI$PTodP`us6+ol#cgm@6xmKigQ?P`H{xT9I=C(Q&KMRGLBtwpL>z#RrqMCa`;Y}yBO+@_^NW)$&{n=Ovm|k$U5c*G)$)U<~U<1irkA@ zn>(U%J-_`Cv3>&&;TN@j)2rzm-JdS~$U^lUTu)w`!i)h_{>{;~oSE1L{tEU&dG;x| z`vJ}e8g$3hR*N-5i_6^6*kF~hbB3-c=!c=p^KFI(R^;1?u9H3po}**1`(9U-YyK8Q1Ba@;@rB2LI-KtIpfun>KqQC?~|e zh+f?np?M=uIlZ*D$yd-}VNIuciu@TDpWda=Ynx|2mM#W_e#vUVAQ45HcW}aJfG5;(xJ8w8a?Ga!9rMp z1`9OGUfCkePN2yt(BzinOb6Pfv3Z}w zqa5`xAHUAUoZom2mFlLineWX00Q%Yh9qZVhzRqrAoOdnfS)u<_FEO8M<~e8B?u)T& z3p7g~f7tZ#?fH&j>QgEo+o5=_VSW{TASLYI*uS%8A^d#XN94b<(``$_%XonLjlzsu=Q?d!t+mXp>W ze*sEVJ^v2&x7fPBMdMS?Q|X{sA7l(yY43B4A&b(VK9|mwM1EdZdZ+qaX@hs&ny0?! zcUQ5kg>^vS?HbyiJs|ioYJ~6QA(NE`Xm`J^Q{x7}uV%F1=Krq8zZxPsoAK z`PFVcSq@xP?!KOW`pwo)_kwA z-KO$;cYZ^#M=qkAQ0ZJ+&L8a1GikfF-|&h#pSG-_SD#apRy=Q`qq?^L<*${F^~~DE z%Qv2>dkS^khW1Nxz2zeJg`J+9sChvPJ`qRCS}w54^o)meuT|#MOW^F+^lS_9H|@g=rSp&DKPk}rr&Z>tTp!+--+qq=BM{l_~X+P`QyJyuN;>r(9&@_ zR~kA&)1gP8>ArVM(^~&`Mb}`j-wkx3#Zzg!KIUKw7tV5-8VG%n`t-k{KFHp4HsIG?@2=cw`DhTqD~859$E?%p~1J5JPd)N6 zOIfgTU!jh-CGvNuPa8i^x#}0j6%lhjX@xii-J&&q*ZSqH+WijbVn!|PW6jaKlXY6l zr}C^Q>-4*}&M9&@D~u;qKTQqPJ}~tD{FmOYZq}X?a`^TK@VBUM zN6%?3*6YeW?(6zq<#16R82&W!!05`8^|11d)~P6WOFDPxP2LS^p86hHv#pf3p*Q$I z&sZw(!5M#}GX8`eTidPJonprh{pao2GyX<#1uy)3Z;&@br^p+8o$t_&Jy{`BTx zF_MwKgY)m$K^-SUVn$>Z$44}jM7nGJ` zpirM#2j6{tY9``i=(0THfFAm(_5qb$Gp82Dx3@nD z9litGys%f>VcjV*>zRCB_w;o&<1=5MSKrUkp$F^y`fhwRHqq|7z)(lQPh;fP#(XZ; z`S{LQbADf@3)##ZncC&G_{g)Z_};O#$m7%Ftf^Dp8glBeXA1iUhn{*LYWZ8+3EhlaX!R&b`3TztQC(}}F`*wWpJlA$Gud$W=92prjW&6lymQ>&`8DD>og!`N80_*RTIWns| zW%gKdMgX*TQCBCnd?jP%<)LIe@Y}FtW%`<7&M)HBdUva|>H6g3<=#cPYl?Nmmx52! z(Q_=a&$#aTt&GJhG4h(K}UyUCXJ=fXQHr-lQ{^3LSO55;X%4Qwc|8Z)0$1v}PXU&v9UP_zZj~i%- zH1uD_x!+gfCtk_C>=k@__HwE1U%}escA4G(0phKa*zkkWKzqxEA7P!_Pb4wCpR@Nz zB{2N&*yTTy+Tou{Xn3E@9{vvr4?k|=SCO~iGp{DC3|%HwxBf)@D-JW(EtB&8`zf2X z0R3O5%&+n7PGoKWeU!`mL;trZcZ70xNUZ-}>c(E!p{vM)Iu23Cp)2^t_T>^BS|Qjn z5*orEJhV!}lo1=)* z>fl+*8`-YVQFFg0^eXSm48L^MNfY#BeyCZCW2by$_t}HR1{<8JCh+z$w>o@;?s8}K-;yP|p8KSo1yR8TO zRkY8}+@`rr4V-xpzteLiyGz@uHp7>$sVnT=fESDnq377)gEixNJ;$ybe!6SI{_ORP z?{tn#=M(Q_{|jN7*O#sVH_fAz{#~RU(7rgHmi_XjwEFFnEsRIEPS|sE6X)mhUdtri z(RZD$z|;7@LP_;O;Dg><+ME9`W@HzR>mGci8}mJZH51A%?$5_x?N>jL##cF^wtsv% zazTAd%gB#$O?>&>$92z3JmEI|OPTfn`M&-6DTREA4=wMVvCRFgrq{Oichv<-ZT(Uo zb1XXESDYwA_D{ZzoyQAJpJIiOJ7PC+bBU(<_1|fa3_3^ykQMW zz3eXfNH^l^;r&Eg&(Pt{lK%=?WPGl)XoH8wd$Y3&6fI=*|1xK^*gt2bE&g|Sp|Sb9 zFCvHi@xa~=9G;G$jk4P2!oAu_-bH;lV=;JG?4~s}jj=W2OSZ7e_FAb=E|mc9SqH~F zPFZM|Y{iFR&$E%E6%BVu1z~5xlNtOW5o8e#aiwuC`z)Kd%mppnt!H1VACim&ow@1yg<@-Opplblx2y z{Ff=(tNChMHQy6_9O;rw@f^`fg>&4{;U#-z!hXR>SIi&A=g8Qv_&p8tEe+(4*qq^_ zem9@`L6i8$-*`5~o6-H7ol9Z*XOdWJmjC_#O_k@+!T)-mOjEz3Ug^DO#k^Y;m8)F-yPhA|{1(w}o$otSNpkw_;we+{O3px8MW4ls}zI z)U!DGt}$yJ4#?_m&I$$_#pGe=`NWxo`aR+Wrk^=qNvj91e_zVaZR(X_ zVyVFI_oOObd^BaV$E>_;PFH95@Z!LW=XD*aKG4;??Eg0IIm{{^zHbs}9no)l>KH}J z8%Mf2pIo~*@V)I_N0y%7)jWMs*Pb8$JMl({*Gs&SVm#`EtnPgH#WjIX&uBdI%(uFl ztDo=MV_(nNxP0^TvTy4*6XY5rv%!fyWWM*mX5N|a2J7=>g=gO-oMFmY$Je5Bt`05W z+bJ(LcET^GU{Rtu#YOSZ_GtaJzFI%6%b!XEE}g0JHF}QL;Z(&ZFHZ%Qek4_SRZnVC zq#`vriLCN*=0#0oYRbQ!m#W(Myy`#Jl$*`u9AEp% z55_u|UK`tfRd0OwQ{P(L|HHLfKN(K2UiP1Nu{Nk)hM+B-3wxM3Qs3uyN%{0$tcR;t z8D?F-iZ#Wz?6N+-3c3i^SeLd(WYYRwavf{6+S}{R9C783c3J1Q)mu}T=MC)M#kVW! z<=0J|>HH7747M*e)gzahEz&R#jLevh-4Uucz6)7ZBa^2$TdP;qTbC$}x7To%db8C` z-VOTPRwI=>&msRReTF9jJlmALZyv!1m(y?Mq1?hlL%-U>Zm%-?eU zmhsodpPnrZcBQ!+GX_ov>y@6_j}TUP3~gg;oGhp3d{E`|sq&fiRK3Nt6XeYt&eC9> z^?zR8EKK>Ji^ay~Dj%Pp3her7s$%9ft)e*5y`hG2azx;=5jR z(qNls^@01&%8Bninm(?)!Wrw&8k@mikVOT#!Q2*?)=l2zJ^XM{s$%kRs_M!sQZIz>CSVtQi8I zTlCw@r}&0dj~4y&rG4B-UMx5$sRE0Q!+M_Ek%2vmET1j zW$Xd9bKc4x=)xYzuoki+(knNI7qWJAfn1_`EL_9yf<2H^d!U2wOrO9LLe7EByJDjkSaI%qQlaOVV$g%*ktO8k9jw~ztP+sL} ztQlFh99cFGSr(}MY2y)O*&bxsc4V1e%Y)djr|&X-&VF##a}?>|^k(ypv(cduWK^|@ z)5!SNtP8U1923qOTN`FI z9L7_O378YbZ6Y$hUTqQN-5S0twgLaalXbOfHxBKpGv8~QC@)SaC#d6$TYYsQQx0cC z-Wsi&O*vsLC*{BA;Z(W3vT?(UR@WZR)c3~<_SuH$lCC{h9MJFjl-`-WB1@YhT^p|X zOyeHT($~w+nfaWBBEI_G;{7$&HJb0uneh`kMb`|eUut+x-E6J%uw56@vP*T=Y}8)T zdgB9iz^FLSeA4$)jlWpuxJvQVSE=iwitP*6cF5^E7F3_!=#8Ac$bG1%u3W|aE{x<5M_odW9?@Q_${$JwW1-z=_>i?g8F1eAA z0|W?{z=oWJARqxFMgciOxG7=;wA5EiLJ~+cB#{I}YiqPO#S+mxfHM3{mbmZOB z#X7Ix+A4Ap%ii|h3+#lvci>JNYC`5t?)l`oooPdmZ(7H{Kd!Ln(azcF9UrUCt~-n= zLw5a5bJLi>4DTgl|A;n|1+);+F%15WQ8p-QOpC4b|aS)mL9)Y(fyJ}|Fe&grZUF|qkG2YwG zaSF#%=m-6F@?+LEw%^tC8+zCHWn&ldJzmwkKZx;;TT$TTCpxdgDt_&~QY|3sf7qw6 z?>m83uvQI-1`c#lP+MoA7P!;p+4Y z>jPG|W$0ACE1#I$uZT8_JzpqgzlL>2Yi@zY->wRDiw@N$`UvTJOCR%&VBObtb}HxS zl#|~6J3o+YUH2u3i3hvb|A5**s{Lnn`mFU~?7zaa6&E;Nzk6ZBpzBl+qd&fcbvn0~Ww*=lScJw@W8~6IV_;7-{+K=}9Jf!b(>DvNdvv;a- zO1fQP?|-u2sl0zaJj%U&J-%0|=h^m7!`!lW*ZnT7Dez7FwI|>GweO=WI5nJh)@j(A z@`0U8!mUPo81mgX`u@^o%++uYKJSR`YTN%X-mM*dyV~)MPUHX4p6V}c=(|5%Y$t{Cma_$rW8BYhVn6Q42M5%We&m)jNwnEKYh!@+*dwC zHAv$(Po*4Z07JRl;h4n+-8d;t^WQOcDn$()nhm6_;xEj%wG2$)n4sf z^GY*qe2?zn`G<|B|ZbHmqLB z{$h-KH?^<9JFTm$F69fL*Ztfi))jER6A9%f3s*A+Vsp(@e5KU%+}IjIzv9O}dBQ&X zm!N-)nN5n7jEz21?7SYCkjl4h-e(?W52SEvM@RMh+{3Q@Anl20ZFbhiA#t9ID0$zX ze|s?hUa0wZ+6sLy$b?saW-d$?hK8Aet2gpY%H}ylf{s!mAwFOPcb^Y zoqN-V|Ov9=yWvjN$+I?ahQ*W?b3(YIUEB?8Q2$RdXqJ z;U1mB$%XNLY!I0Ks|&a;JEmXp>Y?m^CitFlIrqT(`>En1-ReDR+Vj*ovF`Vf-o0`< zuL$Z^|iTP^Bb~%4S)FfFPtnHS4WYh&5T~1f&lHbg>OlZ>^Xh4stVjM zitQfUNaSH{fAY~{o1Mpk@9*j!L_emPMO-t`pROC+Lo8#w*;rOfzo2Qa-mY7Dbu zYrb0FW!=8W?v>d(^K^a#jeZ?=ub<_Q%&Z08u>3&S>!jEqBdzdv@s<6GeK_L7-22CM zf~aeJxcn&giyUD;ZHmf%3GA2ne`vqM{7ii~Le6qu&T`}||9>f`UDxxBlI|g~>tx;A zVaJ1ACmZe|$uuU%?c%kib-00FJVnpygw|_+hVONB5Z^WkF63Mict7wt9(-k-mz2JAA#^dza9Qi=3U$Q~2_7uc|$_a0M$) zqpS2lSJDr9a`hZHvc4VYNqApR|J`@s0$s6ww{fdIXbU+?x&OzW%P59vF43H0Wn!)g z%6T$zk6{YuFZ#CGiv#nj^?kFHl7ohCoRz$I;8T6$%%mL8z5FA$NbZnH78ItsoD{?u z=R<~;Z1CrU6y^hcOStoVY}{wu`(McO@dLFM*IdB&Q$J~&!hI4cE)v^5Ti+-=i^~k? zrf?p7U7ks7lYPVcrIW(PBc{(|9iQoaSJIDf_qRjT|62UgK7#gI*h2{R53X0-IidQ8$J=;?#wz18Uu!Mqh`8=0uHI1lK+SObeK>pnaP@|_ zFVOwOt4{5gWA&$diX(=7NWKfV;pM;Ue&Q0lzd!?>-+=40!pa%up5Yo|?Y-!aHMX() z*36mJd~-gW+wL%L?$MfMYjI(p)Q$sRke82kU0?fSiG{{t>#$1%+co0Uegpk)R(~14 zlQ!<+d{lE3f5|f5=uyUf6_ZVB&YjHVydUpt`c};6lUu>Lk6kAi|JqkD2XI~^ex299 zG!OXeV0--wy5tUIJwnfy_Io zAvfQZk^a!pznn1F7yNTk^mNd>ci%f&-G%zEV2{SWFO=96jISg0SE2q`{mtl?gG|tQ zmmcTP4svkc5b=aLw~TcabEMtZ)Y^*cId*-ewHs?HUDvT|EM0p7<~ugo_>rUiNv*Mt zKb3V-xYtQ`4=Kbq19d&r?nUCmI+w8PD3&6`FZQhB$lLCOVng;|H*=M%?>8R!g8b2J zMq91NpZfX1z-~@P`C;d)CEYp>>RTh;AM3^c;k?!9mKbu@4Db6SvW0Z=Wj=b)8mPMC z%OlTS0?ytsR*<-&=rGiTZ~~aI9yP^@yUGuvCDvPWbm9_xqo?a%;)<@2F-$k10HZj> zGi4uCSGh+1CcHP#u=leWfHB?S&o%LgNo-0OgX3j%UIU;=J37UG9X)ftZ<@Ex>l0=@ zb9d2@|7rZiqY3-YhOX_PtCa3(!#Qg#X54*U7udI*eP*75_1BA`9$Sdlt=8vL(a+t7 z>xb*OgA*GL*HQIUp6A;j{1LkP9v$lPcbKlQUG_A=DpY0DLi+CM z6F*mbMaZA4n3zGIuHrerR+aOfx91sZ#)EXEb+Pm%y6yK-_lA1tIR$GYePcmS;70^v`z}O=5ybFWGo9^!}Gs}cPWGt+7m1q(pF=ADv@(x$CrZXM5p=?91C_KghXCzNlEXDY2&-+oeiJD#u@zetdgz zF6YI(?rF|dt0wQU&r}_4uJP=IpC4K;w#q&lU$T*OW3+}NUg_Lfz8#;u&)`>)c=ZSS z)W=N=b!1G~zpsx8>bdM;yYZ?#H~wN?E$21)BVRC=a}GS2@$$V1(N=1f7BF&pPlzbb z-+K147J2V;v-9cO#UnOtWN)RNeFg3tQ#rq@m%u3u)luRc~SSYlpXPvZ?K=>=`yI_ zg;tBbwC}wI`!sRC=w_ak-^jZq^d#{*{C6#T6G?2=+C43@9Gk9y$IX&KJ`*o{nQ<4{ z@z9;7%;OoMy_elC`HJpo;d5hV%e-q!Ztzr#jRF67stGQncUasoG4;!e@R)(z{OIAlr zoO9wL4g$Gx?YVrr`V~NODUHV?@ z)6!N=-s?j9m#*U|#b4Z3YwPkIL$5!-O|Fjac}%$Y%HOsNhi>PozVPs$uQA9t-t3n_ zFVW?k+YebC*|V8D!9u|C;+5IN*FdMg-QOk8JBgC4HTEQkPuZO7bIxVLT*FFW?W<+umY=~LVBS7HQ_+?^mj*u9cNGS$2zN*sOgUmZ>0ZiKFs>S!q!%v zkL}pvx4X}8cNRK&lvuH*dh)r$wXUn4{K1v_4x2H=cgCK+UjzPN;hgr34{^_T;lKB; zKb$uy1bQrxx^aYn;1Gk8+UCU!nh4RIF9`{*F?T@O&Tdi$|bp^B2w{#`KEOBFSuWM z<=ztRDR;G&(76q~2XDG_?^^heT>W$IX|CE+&e}JQzYhokoP!)L8!! z&Lj?|OU|!`nxfS&AusojSNHG>R zs;fWEcg!O@75nvm=kgaiK5t#meW>_Fk8XPB757@d!*wF+t8Q<%;}eye$F&8OF=?k5 zCs{FMFXuR+1MF4utqA725noiBV%AKhl6!7D<7JR>-a`NJ-X?+#VkPtb^@|Ciggtk_ zE+*(3M;kvm&eqz2V*)V^y2}i=u`Pn1D&ao`)@w2=vz6a+Zxu2O9!!=#IC;XK8Uhark1#@I5_LP|i zevp3;1B(sea#~r>PvQJW=lbE{TQD6nt^Zf%--loh^fb@LM$Ai4rtLt1`EG0kK0|q) ze?_<9pT|bT65*TJqweU_*0F(ic*?&sLkHT1ticw<#TmJY@Qn}NhJW*(q;Na$M&+GC z#%%71qa2I9iaYOXOrcMUaz}GczQsHCE9J;Ng1HAhn0q3=mphvA!85(K%&0vp(P5Z# z&EUQXz6mo2mx{B-Tm3x~=lp-fybAWPuQ2hR?IuMs|AF^6h471c@H*p)UdZiu2#POUCN>4etjX?T?Ky8XMqF z)c8Qhe357GTKoMx;)ljHvD)zLgt?*&i?-^VD~Y}(Yh;t%`{CVstJ3c>VsOe9i z7+;_|ld?#53aaBtA&?qw-7f__0^O8THZmah;-?@yh#4VpoK@ z&&P!JRGYNw$pz0V-j+=MEQ5PpM&u+yzuHq{V&!evlXDPrrFXCFgwXh#OD4ah?=^H| zH$>-AIv?q&KH5Kf->BPD^QXSCskmOaa{F4vkUa}cE^mr%xA8oLKV88+HW7D=+95v* zo*BeC=Irnj;18;v>U;5@cVnQJ!a3UxsvX<^ImVGr(B&8EEBaLbQ-i(-<+|$gkUZ8_ zrS$V5;=JR{J4&f$%i!TcpVW#BV*u2H-t#-O*a z7C!`T4f74YS`NLoa1Lv2onubXi5JK*Uf=JTT1Vv{~{5w>C;*fWE9;%avk=LM0_#*L%+^pvA_jfH=4Kx=>m-=F{3 z)@cpB+_B!ydCcRiMap*UJ2X$fQu`LP3DNO4(}vy|YV}^S;U&|hOzWIB_Ei0~j^(lP zm88E`vUP&BlJ+{g)U$KGUw%tG6y6`Y(+qrT1M?DX(J$*CYO_n79m>a7?zA>AgEmj# zUEL@5+!wk%w2yQ0KJE&0qdQ7|VUJwX^X0bpT=_o3zGSe@+nKAiiQX$}`g-S;qG_Dd zhAY{K3B|SydY+)~z(Ox<-aFruduLH0^Bneyg(_l-4Y4m0I=A8aEY}(ZcWEnO*D=_T z@&o-fN2!m~_Xq8oFFtu^D|x#f<&L zA|C4K=s7erk9JB!7smMJ$kna!>YXd(|LSww6zeNR%$Y~VF=CFM%OK_u+e77DVpzzF zVf3Sjao68FzxQKUPhuG5Me}_oU3&z7h_n7+&s8>)|1hVpjwDXp(9!XSp_~VLeiCI9 zT`|J5xp&;6I;sm#-=}vb`?PjEWc5faX3Q>=U9?t=SMA-*TEMVn~i@Vr8jNL1E{}iwso&=svi{=hl$AGjZ{ zkoP;9F7aPB4q`t1O6~Y7dv#x*M8_uSw97bSJ_w&{$13*a{Ha(p!}^tR%=z!mjj{>j z$velIx_6{k*V5YIRV|ouyH`#7V7)Cnb#GjCHOD}==WWmrteU#lEo^>uzi5SXUe)*M z5?|cMY&?yEb+?PHs^P#SK-$y?SgCaahwA(#txUK6@IoYT@UM0XC3%z z)zi4=nr&Hmg0+~&zVUReIA!_9O<5>m^UFP2WZ&wznWwUSaytIOyc|Jyo-QI?b+Jpn zV`H>E|HdxX?kjg`-IuniY_HW7@qUDr`|!HOl$i%!=dN~tz^|JCPyCL?IXB&WlzKCu zkM!$l9zNIB|5x5i^AC6b;hhM zC>-;AtJV(aBEcHK#@JP5-r9v2RD|&zCHf0@r{Z@`yO5ELjQrkHf#&+v(FiB;Thh|ysK~{??i2Ti#@})*fV4gI{6lR zhU`mfAHPZSaoF3JY!BAK<_gZ?{Izhft~uJeHz)BW@0R1E(snPSb1iG_Am6wGzv!}# z&4?wwOfa8jXkF{edf0hE%zSyG*2m>jbe+OmyMQZa50Fzk&Z!PCzw<|Y568?GZ*0z0N6R@8JB0 zHrlm^5;LDqh_BqXnPXP`#ceA%M%eFcvN4;!vzM9B`AcE*_I1cn!X90hcDJuBoU?r+ zYoiFhrI^!A{SUc^Vh;7?1GXM1_LM%Dkj`L;IQJS5saw#iiUk(uHXF z0edl@4}FMOBN$qkyzA*#d)coPQ3suS>wL@mh_!jwb-C8$cHP6erHhSPyUL0A?72$P z-P)RTe_4@qf8CUHUo20$FKkY_FSQqs8GBsG@#9V?J+X3ORdo$JJ)M6Ma*?F_nl7p- zZ^*kGnEP$Mhy&+(Hebx4yPq%R$aQSPRgBjXeqMEFkheZazMQ;E5`I1h>yzXw$PXn6 zU&|ri&o^-#=I2*%RNE@kN=lN}lG;f0>9sAQ^&YvdA}7A)ao~2rTe4@qd+cKuJOR8z z@D;7!sJgE7u5{pif*0kj9evWR9TR{L2p&1`tJn)oKe#yQ{!XA-8J+&jkMC&f2OJap z-iv2tev-EPC16+ZPtLi1-4$DRy$4(@_`F;HIQzss9bW<`1h@3Rw(r5e?s*irT=4hz zUKAN~&coAyD+F)vHsg!W{&80bxJmHfJ>{3*vGHf?fLjIMeaZLl?YVi&5a6|f|NZK= zlJsYGRRgyP?!J1|ZO@(d_$=Vff_raih>zdX^E}|Kf}aSN^f`O&g13Qp3qB#|H%$vS zmmC1zFW9;N!t-|iVBm4U2L(_3$?ex}TM)lB>AoHl{I}~~J!yH_YiYn%_f2gLn<8tT zdk45w^s^`YXvMZ$3Z4U=A$U|<_B;I_FZ~>NzTlVdbe_NJo&kRZt`$7yFa5s!bj?*~ z0k07J-S=|eJOAOE=>O|U!Eayi{KJFCpNc+TUnlss%+W=gYCr!Nc%$Hlj(z*X2R1dX z0^TC{$)B7zZrB;?Rer1B{3{+x`TV2gCBVA{Pw4n%ap?8uwgc}MJooy3zn(oK^IqVC zf^QvHmHXJrq43+CCisLs!;Zgk?M>GK=L&vg-ue5NpZ(jhz(s<;lXKJiCAZBf1}+tR z*(1Mw?BP3J#OM2NNxFUT%l}R4i+%ex{r6>aSNvysZjndpmwTv8Ux{P>)3`?73dVjr zMWQOF{)4Mcy2sL&F%_U3l5EbkQqgx~bJ0h(C*9HIppK-|w&)|Ek7zmyy~v{vqn+X{ zN1>N`^!)i;@mz5fI{Nvg`1hv@V}^fQqCg!ZG*6CS;6 zU(y|iFTmpP`tVi#*=tD&KlF9wUje-}>6X#2vUSv@%wg>}K~E;#lXsBhD~g?6>r+?s zl6I2xaRhxg?Y>w6-jA)X&!GIeq%D=^< zH&gD?qsh0`qc1&}beBrsNA_KCr|jTm$LTJpX>ytak@u1LCTo09G|ZJv8todtCCAo?}MB&sDyhtYR< z^wmX4H%S{`qwn+RYmn>v#l{i;g5 zbl=ELx>q2_mDnqGMEy5h)-bIg*+Z9pez%tL$a-r<()~#;D3_!$<;(NCHlJQjnI@ms zmA=`hCz9^Xo1sgVuJoSP{kBrtZ$Aoszeit(tT)l0ukkbyzXt$uR6dj^ND{6$9}LH+e@zJI!uv+`wJ)VTD51(o&nja5Yj%SO5d z%Z9s^EpFqYMa?xWK;-z%Fe>I&F0H9_YgW`&E^BV7sfL9y%WJAy8kf2)ODmT&HP+WP z)VM8;jc$Eo!(vM|4UO)y=E{ZjHLm3_=akdk%7u-~DOOwK)-9=A%)X)iPM=vmcU0Yy zrcuQ!EZor8U@7kDlP&C?<{!O-nNw0cM#h_Sd~tEHTh!Pvs;aiGX}DR|a6v=kMGfZS znr5GmJ($^NxJ6USi`^-W%NkmSvmjnlQ`x+1X-&0Txwx{fp}EBhRNF|V3SC?<+>RE? zoicasS*K4ebKh>g!KE{YN{n<{>Xy_sEN+%s+@&@3l`VD4Yl3>N_t!AG(re!XjcL5V zgQuM`)1E8xP_+H?n==#t4}ap}&YUxIuDh_Np{jOCB_?ZLR@YJkf%d1ApXEv6x&_S$ zyd1+Gi-ldcsC>@MYPVno!UIkF&*i4goZ}T!xmjb}s>&+N=(=i`lgnl9WLG}WJlq`( zPJeFMVfdh%w*J^I^(z-P*EFGP$vGX|=ey?%Z$AomplH08<(p7S$~V5-(8?{S`^lN~`gf+PY?U;j+5=YIjLv zbxnQqcq{e=HA@=++{%V(!5N3@+T7yC`s$hn7wuME(7bGk=VKUfR9!=LO;Zg&(ou7x z<<(r(NZ*g((A-j2U+?1O4bARFwG8RH7Pq#8Rb5!^*}OF6o9iNP<7_vhA+ zomjw7Mh3Z^#7bBKmKYxiA9a|b(D(e?4S?Hs^_(!3`^xJ82&E3r|s;!oeix$;f zq@!na4T8Y?XkQ=-^y6t~3ju6Zf&BS_UeF{n@`Bn+JV_L>?7SSvYnKf{E%Eg_lfQIX zL)S5$U)4x7ZKxzM#Zh^-m4 zQ){$qLvfAOy==wcv|ib%zXngkep3OuYn+-oyDY0mOR@t(1N=l0DdWM5N zj^RjVPRVgTJl2E9jPs9P!8xTCq#StUnp1Lue;jwbg|$8s{&eu-clz-#GUkla)C;Y< z=AM4ayeV2Y+P|}is8gq$Hnq%$=bkpRT-myYmeG~<%Yx&Ay80$t!pDy*@yiP)P*m3~ z_Yi^?F0DkFUEsQw#wIVES$@^EOD}G2@fLiGnwE`juBv1>FR(+X3v6o$hI#XaOKn&- zf?0evG*>Yx(uClPYHM1$@?-ckRaSWmFVQg_B6{*L97Yq?u=d3Z>c<#!7(DiHxSB<- zSIfg!H8x$`6<)-Q+Z85^)>JN8V2g>b5376rs@LP=<6D;2RoXs_hsrN&VCAy7!LGCg z)6MEeUxKh$uQ=YLS68)^t|;{+ zwDoJWs_Ft06IyCc#5)3htm&H>Nj_X%N6=McKFrk9(zw`D%JRDE(MuXNXDlEza9#j> z@v`M(kIy%#v2_Wlf$-EUl4u5rP|}vd)t%cM%hErR$%CHP<(Kqk{GF#m%Ez>K86pQrFyk z5{sR~YF9V1?9&o;NoA9rNSD?u#&T+qdbZu5K5J_WuV9e)^iIA3OhBz^lIcN^x8+se zPGt)g)h}zVHJ-LTxt29pitU)n)z>$Bm8f}gtF3M(#k^x8&4&*hI+lO`^&OM;dGM6` zpI@?g_Et0Lpilo(+ii<38~^g8*UqwklXm#{cK-;U{;z*@%gH^C?Y6)0cR!l+_l}O2 z%KQIj@{;~H+)0t2`^SkF-t^7`Jc3NX8d~oC%y4w z{oOq2PsdLF>a!F7K51VlbLLauI(|yA*X|U5{7yQ?Y3tAbq_dx|@AG_p-$|GEuz!;_ z`0f1CKmNVr(!ahx`@yeHcy~h5EW0()Z^-BK%0}f*`qVon(!JwzKHToZ&z|$Asf+(r z_Rh(_%6n(S*}p28RKD=^o&UJ^i%Iu=bk#F=JXAF4!9n(K(!+kckNW+3((l(Ze!qV1 z_v_bwzsi06ebYNmIzIBxlkdCl{zG{YHsbW4X=_$ta@gfSK9lH z{_Bs*gh=wCNdgZ2#aj4kaYQgGbN-dbh6wX|9h@vY zB{L-G!G6mKNV*<3D$dX30{!$`#sn85SD5Lr?Gv7w8Hxfe=+{iyUgTDci9{L7Fb40` zhxwTk8l0)Rd)i|1m{<`Wr8Scg4MNhX` z{zWRY?{d9+RV6(zzyeTOYmNFOxA{K_!Y-hUM?0M>sXbf zkvE?^Lxs;&`5!y^%EtD7@L>JUX>b+a?NdT ziGb@C;|vgOY`b*`JVWg?g6eSDH+{WY|j<}J-S)So^k&m;qq6clUsVfHz|?%iu8qAN24jn+b8wu})8G8Y@PrxO|d3(3Y(Q2#5Q5 zEmsT3?(YE=z8gf+h8av9UhWKsNBB$fkuA>fetzD$#5pFwJEhJs)UsvF51bJJKD^o) zLF5R3DV8`@RX7#FUdbZU{{wCPXgBP@&_^crf>e#tCzS#qeoG z^5;3TlWs~axgzIQ_Hdums$Z`4tI&c4%Z*cRM;168Gfg&ySCWH6G}S9HUpm6c71qqi zZhnExBZxB~PUC(8$eYO0pXhL}$Tx!)&IVs@OKc&RMv2qB66XXZTEI6MoTmHTNjG(* zQQ$nqS&RVDH5!$tfat!N%$20?33!^!8q&1_ULf;h(oHs`r*VxtwM0AJ{IXzjob#iE zo$kXxv|4m4=og%NcGQnibynfLQO1}%2<+V_keLOgk0{can70dhTA zEG5l3%PBEEL46^V2MSI@ZIQ+_XP%tsHwU=l50AOvd8q+hDxD>CFZDikuTt#KBl8c^ z-vult^Ev5L0T<$)L}915fJ?~?A#pRQ>3$WN5v1V)){;4abR2`W`^};2$_HTTo6I*zXA$rL8!5QTa2o)>bodYS z!6iCne<#4G&UYzaNm_8I&Mqs&F4fsboq0hWiwWwm6n5&2CO9kBKC7wLKW0ctt%t-u zM91q*>zJsei-{y(Mrsxy$uA>)heG_J|Lo(FZu$xfUE?e&z!~pS)oWB5Cw8tTeP6(t zWPV7xPQW>2enPrsI6zhCx_JqXC^o~jj(VfB048ati_?u?6Ouv^5j-Jp6h8_1Q__Mqct*Wtd`D%vc;4}Kp7oaJ9Ujj+0-i6!<~IS)*8yG=Ph(u1GY4l}tPDe< z`wnGVk@+9y6pC$koGB>|BR%}Q6<`m2ELWI9Nn z3qVC7B4McK6aW}UKh)JG{hCb2IX0^d^!ir*R#^77A=H%dbNy`B&u)fb^y98Wa0iuj zU$^Dw%7vpYn0XGdH6!(FvW6zm{z<-=q0<0n`eKG~h|v5%%<};jcJghpd|TjK?hvap z7JQvA<0kZjfbT5;KMwfb2e2{V`xL+{C#A)%t1etIKidGlVRK{PA zBB8<2Q8D^oY9oUk-yLk_*XpGxI^Oo4nxF zb~C()iVMANx_&pqguU>t-kJL2#QSUMZD)@hnl|;RHNV zWxF{avfs`8pqo9~qU?hd48QfN*XIYcHo(=SS#?7E6GQ{gyCvF_L5+n-mgNrYbB_dHoTu=6T z1~uqep5L>`S&-*?J@attnF{)REK+Yk*J}9P<;+WS&gO8I zMqzjhg*xYY0HS7OrNhJ@PQWkIxiz0d-AAyQt4JLE*fujV<$_}KZ>IK){V5lWF$Zmq zEn!MDyh_=-Q(B76YbttnO3N7YT9(aKH#D2qFeJ#TV)Hx8DWz(R`JKpv@X??jzU zLuTyjD3tXKES+Z`h2;*g;Zcu!l`b-mXWKelrZSJKdz+nvp45%TA4ZFfrP! zb0*-D=4`|-O22$yLPVHPB25(VHks)pdLUkn6l|hkj>L@B4hF?K z%Azt=oPZKNgLJxV$Qqt$IhW$IRNREFGIrk~vXjwi_Z_0l+1hu=SPOL@Gw`cnZ>Iqv zO<~yEZb;L1LnvFmKQ-*_M})oIiLkfT5DrO$3(~y}hHx5?Q?IdC=oQc@R@9lULX}B3 ztC(ZL3iLT^zUh*Wm1~sv7+vTrG}DLq2nJqsh0|cBV;6_cMXx8V4)LH=e-KC>-AGy= zy4cKQLbix!K|B?zGp8~)*(%cI4kD3p_~@LKy;_2eLYBy<6X~UMb<)k;2dZ2WIafQH z+a@x*Xla*%O;R!(O@R{&J*iT#cgk?2ny5CBD&-rbGegy8lDw`FpqaEJ)NB&Im?<}a zSVcHe&z);bW<>hvSKznaO{2yJ)=-9Ry#PkG^)1wU%(h-o;J5xVs9$9fo(il|oU>_o zSkUlaApVJli-Lw(9i@DVI)?k|NJW6uTuoh3*XiN6FWZ}g&aJlX9)8=YEHhGXa`;@4 z%w7p_Kj|L&-2<;zzf;>uPtklYzxmWXAa>JQPSDyHAohnYGQBk_P*>VHqIPwCO!>1v zvH2Y3ANaS;Ys^N^KWOsb7=F$@lCS4ngKGtEHD`pD8MfP(Kv4zKT4m`Rbe|Stv;h?hwZSm`iwphw&T+3GkSj54$ScbwTl!g z6|-L`_lW0Uvy^{^&}7aOY3oVKk@=&RHsiH7721ikjLtB_Gu+>kR^!u?Hf3d412jBX z(nf}b?FgNkW*gI>4?TdIoLj=)Mr|FeQvMx_Fkr*;Evra3h6}8+xP!_>x{Xrvwsu(O zRN?ugB{XKH4in4pc>~c_K_qji@EU~AubluUKQc}(I;%*cKAX_KZX_>jp>gu9Y*ww; zIdN-n32GXh0s&{HWwA1J3TN0dSwOy+vdAg2RopD?-8#c95VxW_$Jk*gc(}isSc?}%?{FH5L{xs7(`Yp$ zrCtZ}=T@E*bP}FA-nme#`$r_o-gUy9=q$B#i&=Yert@d&Mf+xP^QUqCV$~p>rq((i zSU@^WEpa}iQs@zDzKE`WL}iYVmQ$7lj1Gi(${o&MiLcR-V&1-+Vp<|c=lTL6aq891 z8weDgVw;~&HnrPW;AQg3GtF>*&Ec&VW%exJTtx+;4e;( zW9Z$=@D%ZUcO*a0icuXmxtr8=V}Q4N&JJwu9|!yvaOjbQ3Z&cs!|30=0`N&08#)nm z^!Fv?Q-m(G#bPv-(#O`*29dwvoKoarAhNrx&qJl&$w$#B8g)Vyn!xIk?!9e1y=k=g z%3GhaxQ?w6>0~M^g&&f>pR-UXwItL|($*YdBrTY9beYzH5>h6Fs$`5a!LgJ`?+Y$< zO{hv{7w$IF^(yyLsM>EJ{Y!BF02lo-R6W4smob5JtKu9Me4%P=p(ZjeBsET991|U~ zhUF|ap?XHGHW@N5C0)Wq>ZT>#2R^2}acV-1OuiXcVgVPiGp-X56CnzQW-?wRwF|&v z-Kg9x6%ThWOS%v7z90&&dWzy{e-MM!P*HWaVlh~yIyV8GM$&59y^~A@>05&U?x)Co zIEK4PKTn9>4y}Q7zJQm=pwe#F(%R4swDzuT?d2O-uBEa&`4TM zzyK9x##Fp1V9*jUXtfL^Z4LCKmG*<{F<#nZs{I{mB3`B|fJ&KTNyTIQ;%jwI^$@>i z-egw=^h1@Y9O&m}isD8PMxrB=dICO#nk8WPV9{ z8fM7yV6|k?&bfOs>zYxUH!ex@sHdMVbAwpybuakesOyKN2F zK1t=r1Gc{ecs_;Fm5UN9uJ+{hkUrD<65rx3M?_38q`xI1b-X}L`4-msSd)N$sFDX~7a!%B7zA1g( zm&OCdXCvW#bSSzVCtc^a`0@&A?7mtb{ZN2zv*;GDKUpsZ=&kC{edu@4`>M9eulA>a zzT47o2Wv z499N5da2xrFgfAHm*W&L#;7LkSqsDzo7Kl1*2bISLW@4qr*kFKqg#jFRO+MO3(zy< z{+nL#<=g}t8MX(*(5qH!>3g6*E4Cl{^n!rS7ZE|DL)*^>GJX2gfSwfnfq?-XBU}D8 z0ezi%^8jKgK=-&jK)2Cz=Tu9>&X)F*fQG}L#i^9)&GXqk7SMQcKj>*kP@U>WfaadzHL@0QZ^B&Zm zC90$)&Y+tqQ$k{emJ3LCLQKrP#*2pc#-@=@7J#qDmXox=)_nKGK~1IlWh(tgI!vEH zEX~rfTS+$yV3v*%MPqlvK+|39Wzut~^~p5Us;TtJVrA&CouyIC6YqM8>G`s+g`GBN zJ~+zBB2m;Vjg!8CGYj=jUKv)*7+T4LXo6pF~Es`9s~$dvK(v_4?_z4b2xXpX z)l#d76c^A!W(H~UsQ{c#Y$<~SC3-z6YAY0k@3ByqcBI=a2c%p5@?NLz=r%`ZjnZw8 zM$!^rw>?-k_6Vl_9&G^EquZZS%j)*0G=G?Gx9szDn^R;pwEw$SLqDZysWvCkIkTTA z#r(9Xi(+1-s;t9s&?v~cAh1qCMYqsor`x{T287q;t%t{@+Pe(x4qZ<_`|G?Z?^VRy zLE0|hS7i2(-W0$pyT^Xgp9DNa=3~-FG1aGb-dk8d6-)=J&igai_qh#Zq9}iZ!i3y& z7!qnYXcp-mLqdNRX|)mNY3kXb{&d_gLQv8yf@6gIB8-~ov$AF0r!>H7vyTMN`wZp@ zlHL{n40g1E>X~v1KS)aofpT9F&kcwu)e^7kLaYa;nEDLvV2Od_tLCKvaivfEO_!QD zu~+j3pSZsZ@z#L2-Xr!=2n+<;6c8Wti9@>(p9zRB_{2$Fh}*!`NZMUK@!T%NJpu7u zpQt53(B?rY0k`-Wj$j>7r{{3`DP5EI^tqS93jI6RN@+i(cXq+_Q*{8__4#!`-)O6~ z`{;cEy4|Ap`RIQK=-n3mg@^9jJwV%;>8Tta9mIe95RsmW`{)UN=~wxf9O#jtWvZu2 zJ(2sW^M_{Sr^#)~D|d=vK*3 zuL$VAl5#uOKeer82Dqp7xd0Z*;)c>i+4?0b5^5{mwXC+82Db zi-Ky_Bv0=M*fJ#4n|@dM^c{AA@$~+H?Z-a-?tpF=7|$4={!E%rfAO$ppTTb}+r2@v z*3v(7ee}lxx=p(KS+URUXA?Yn|D1rnMY{PJmWX~rDAw{f<+=mkWjeHY-xU3)1jV;n z^nAbge9++yeY~>OKI_Jy>~32Ym$s~J|LsI;(O66J_YW39yY^W$wzH)lv7CE*oPEpn z55_<4r!a!$I%k(%2T&M2y>}bP(aP*5Q$*h$^9?j0)t76BZRs%#Bmo8t^3ku5KN$fI*vOQ0k+11ZZo!$LINcb)u8Lp?6_Mc>l&idevoF(}j11$7En|{`1NX z%e%=(2j@RKjYY5bcn@3v@4gtCZGkw4p~v~hu^c;5L9j@QUFg4<*)!u=}&e-D5t=%BTk;( z@f^-0ZJu56-p7!i3ZC8Y-VAIrHJyF-zTK6JBhjY2DQ7_wrds8&v^vwuf{Gl&La#5UlqdfaK<4HA2^(+4Ek~`cV0})qpk6}y(VR+;~a--LyxFV z%B7Ao)b@|FsKIBaFNQ zIQ^Xt%a?mbnn1m)%Oiu|DWZ`IM>iV|en$?zH<7cn@gg>bJULCzI+l+$XHaP$mFiXe zPfpGNW8AQcx3{O;D_Fgy$niN`%j(lx!c*x|(j{D1ar%lTHrJA_GzQKgynpaNZO3|9 z_!nYmVS62J@IP4=r&hFqT{d8$X&bJ7bX#ifqzCS@ZoI|7+?6h_Sk^tc+hVg>nM+LX zZrrQ(v%V-`W;gCt`x$aZW)@Pg@mUFRW;d=)KHEzWK#Tb=tlX9}W+uc=WpOtI6@*>P*tMZ5z9$v$1PzV`^cQZHp=?-(00WovFJrOzOqU zu?#|Tri7EEmMo`<&?B&0VRhZRTcx?gDzDo@bBXI|5jCW&s?kUt&}?cjXGji~dU_3p zFm+srS!_k&$p(`;#hIOzbh{H79B#c~EB&ld4O{|7EJ@JwQPRDmc!h>RR~GYEFzXZAR?0KAM;H)r88?n^As5ZCZ^ZI=yeU?BPhuw}1J!|HhNw};3X z&3RU@Vb$hLX&M$eKOx;RmtyZYb5x5Ka-Je>9=6=f!K6a;#+Q3%5ZbaoMAr|}P%nkH zG*@v?7m}k7LX1`W#A2U#EVxxZuFT>_Y3hyLAe@Dd?ew^zH9csH>)u!+<@b{_y@rQ= ze?X;~42sM`Gr3F|8-TtoAJh%8L)!+lm{N>4w9OJ`mOxnQsyeyoD;i;E&XZkH|9pT; zrT+Y^6i^KR-W2M6tN_k~dsD9W>?i=b?!AIkPyf2Fl(@*2naow-w{l@I5FZ z8tj28G)3fJjm9*rw|=&YXy4q}(>`(a!Fp_y`dO~r zz~1=q!A4Q9T9zgae9*?6WA>BwXaJ3h>AJqz=1DM1`9CVM|7o>+e2;3pu&#jY24`nV z(jAZ>Yj68>F3DTcyx6eDFb+e%PYA<&)twUasr@9#lYN!%E;m9~_~<$E-Bw%|T)mI0 z^NV_G0esS={9VP!7&Nvpnd|S zr;G@*mS%Gz?C=nc+{_>4l@P34rzB=nB@nZ_4wfEgEFzkw~H zgr=raAhMxXp`w9g;~v_+TP53?=Ox?sq>JxM7i*-8weX%yngGq};`W;%%~#XtqVKmz z=SUZOKv-SmQq}5Wz=oW{t0Egmu~MA0v9LcGbEI0HOuD(nYWksP)bx`9R~)79Qn=>M z5-(*cEPG!Ox$AI%+;vne-AWh3Uj~Z!F7+-&5xE<|e&`z9Y~ z5uL#J&e*Ra;L=5we(F&_+oRvmqsVUqE_cGEOD=XpS`4`8?{5RQ1l(;y!4>w<@}rH_N6L~O4dxCsPnhq|?;k;Z#|G%Ws+ZdB zCJ;AM?ECFr>9;kSm+H*L!MttHdAp)7xoO#+$P8qv^BItpq zyi{a7E6TJ1PNmnj>3aa9{7nT@_spVTS|_h>jcBQ4K|d?tC8^&nVb^ojhsNLw=Oz+=^LJ8@##Lv{-3A#WzyFjR=I_zMoPn zbtU_7)XVM3%E=bSs3x38Lw?a*W|LgGOgNAAs>*9wq$#B5X7a1VH|=!a=W<6-I3J(u zxeM%Y`CO}=)_U$2dvFtd96r`-pm4xCH4;xES+4{C=Ml zd_sYbXf~%rjVUJP)G9}_12*(1Y&|^MA0fe1O4ABAqNDbVUgC**_}04VmoXY(J`dqa zk}43Vk@SQ@3YB`hL=b+sE9*9d%SdP9q9ztinXjKJ!kui|+a;KIUmE(LZ`L$NI7uJDG4=4T;W zePq-k5rDrkZ|&M$&qBuEqe%>tHiX{1!SUo)E}WUjUDJ}To^2qXb}IP+&)gbP{u|^6 z?k>Z+y8F_ufxABkpMp1&Zk{`X66YVrDDB&$EkPCfyzWO ztgs}@TQp~Ri{>nEt;`bClw^4e=HZ)P|F%HvXKiM{E>2FVgD#Ku*4%!a=n@9LwijTKSz|Cb2VZi%x`0oh_e+ z`y+&L?ioR5REMUUw0%=3;M}AFAEpWMd0A(T4Z+B)dJ zkaTYMM&mRJBhFWoE~o1`jLQ6tAR{+BOCg38fO0CKg6w~{fNzl5LfV{aOM$rnXdmeh z?6LzA{_^)QOd}6D&0_Hn)fxu<1Ja)b;8pz(l0FfDVFsYM0UD^0hp3PK)l za*dwx6VrGR0hk}nZY`A6LRowV%q5-a^Br&=z<&jNk!(QCVJxo(bGbo>`L(_d^Dl+X z@(9<4uQpvYIT7dlx#Ntf0KSm9YN}>DK~?A_IR9%(Tk~}P&r)?qyk~|_to=c0JF(j`H%mk^nXr5Fn zt+#5N2MT75l)l{geWvtA)9G2fq02bGAB9-wMwMfUVWvkl)Scf?Cx1~GZ`o`097f}N zZOt%aPunzRdMu1#-jTtkBXfHDyUNx{{QKVP#HPQ8X>5V)KJOi)ETcK?D^=*ezlY$k z9hQIg@=GdLaBaq$7vN6=U-|xPB>vmZu1@iXN7<^{HC)nbDVaVW^`*~{OxqcF&YNM# zzqL87T+@3!L1TE9{ltiU{5JhZ1r6p2Z>BPN=cB#qlsfYSv!nbf@B5_h;j<%J<+IAH zBWk>CnN7aOXV%W~3%O~=%PFM^bYFnl0ctzKYu*|0Ay$mGKLE`x z%jGb6Z<2P)x;RYUUr2AKst}fv!wjPPgJSm7M;t~f7)N(JEDmR>5*!BMBZCI`90rX5 z&_ln`9RY_aU{3KkFvpB+!Ud!I9ubFoRcRRH*(B|{$=wG17wMY0N09Hyl|?9Jn;XYY6OwjSOX+>q89+Gq;86m;NoD~_6G&DSMZO_yHJJ6Jn}uxx`)y$_1hbR$5}nTa&QN}m zN%t6pH?GL^e(=9Y1bF@!k(sTK%gIN7bXT`Yz>gqM=G_!Wp>AIR_==0{?r{RHBXbt% z42k+9SY|#8^lj1w0=ANACv8EfOyr2(C+w?W{!Drco|&J5eVpSwQ9k410rT~cu>e^S zGBZgU>sfftkaJ1r7&?);7b#aD_>_xY8TsM%G_yLy;Bdir!W8JTa9&Jl1mnWdx#TqgU6lwTn14PaK1t`N{h=0~J8 z2*SV}U7>-iPNnT92&z*f+v!x3!diB@FX71DkfI-)Pu$6l1QI?6m!Aa^ZUcBpe*A$N zk%Uwkx=Vm0{E)O?01`?kL%#?lG{PcbJ{r&0bMKNce++3jlm;?;%sj%)f>7W824(J8U0unT%BDTd=hLoV`g?$hT<4bLVdr zix6fBT9IyZEI})*m&kJ}h$(Vly%E=0X#GWAy3kg#PLY1aITS&EV=B;}JspW{!YR(7 zrcuY?jdy9KAtg*TSEU0mlj7qP^!-iGdUhjoCP@y{6YItok`Pebf0lH|>H#TOFqqD%g!`T7QG0>$ zD@d&Zwv)j};@85U$J=BG4Dnk8V9PkuX?(N%XG|0Pt^Z_X6I<2)W6_D@%71$N%+x?n+Z@#4IolkjDV&XP zIFG(~(Q;mY<+Pef`v~!Ry7Idj9+@+#8J3r-%*eI{6Ety;)1UJb?FNPH`AM(Wc_qj| zhLTQ33SJ@oCZ*cs1&F_ZcsFIK8RR1h!yvv)S=wv{s~sGsu!uA;rOvpvVE~+<@B*;9 z7o^w9l;x&C-cQkCr~H4ky$6(4)%C}J&wDdWdD9CpFyI?{uLIHC$^0iu5u{ zaijO0wU`s49#Aw8hMh!8Tkf;%RH`tAc{y*Py?|ttLnDzUw|5|?*d)_(woU_k9 zyPa|y(7YSlBf3{m&ib&@Y^MR$WbXBE2G&-Z;WTLOA&!H17;|sv#qj!n2JwO;(mf$v zkH*dX#xPp{-!zsjiCTk^z<`#FcwBR@P6JfZpv*SMuCoWyywES&M$v6FFZB9uuph)8 z&C%KaC=1u@huY#g)XhYn*&k8zFz_JyjFUdIzasZM@FZPlBHS{Bdjx#B-3kH`pe_J#QQPGEL{Qo+Sepu|-~ zvWjIy>jQ)QsyV&lxz%q_Z53fofkCb4VOKmSZ-ZDHeoAt}U90rmT-{xqi;F-&H2ITqUA$cb~cK8#z8K;8x3R0h>HL{bed zv?jBaOT}}P*h@n5P24>cy_a!_F;L5h7?z-;Jv(Lzj*5{KjpyR*J{EYhfKuiHZB>v1^eIqq=K#&N7&6ffTU_ou`Zv-3n^Uu}%cJSF8ceDS(Q{1EN ztg~&HEp)V8C}yd$gS%K*z!R3;a{!qlY`@){$45i(J?&2J!-GlDps!F>D-NpI#%H(=H(ImRe^}|_>X@@}M<3_t0XAp^c z3?D}nt_lo#2i+r~^t@TTl2(|?QJH&h&t=B{t><>P@mO4pF<~AVJdEe5iBU(CU z4n1oEpq=Fw9d1POdxA>}uITiuWEuX6Y8*Sb^1@X65rivI~;4N~%gtYUFA4-l@Op6xD zEKrX!1Dl=X`UCxvS*RZKF=N4u;+n6y+sDiUGn4Dr<{kz3LFBdoWy#ub-7Azj`vdU1 zWY!xxm2hzS7B2%YB(v_&gM=3IHkdayc@xwfkwGi9ZJL}`_Oh#<>rc2ms$#7fNBtTbxhAM-d z0R6mTo@~x<^|vT$4YX8-nAWlj(24L+Nv~DS4_4w&I<1CjS5fKRz&M?r(=_WP1-*2`9%pEKqiFZdafC<#DBO^;LB`(@?VHF+sin>-T z!me7KR8d8=0)`t&<{;zH?Pix}WA;O`_Eb3jK^gfjY)fiyc^D{{+TGXPlS88|pQy>V zXN#b)ONp_ty~-NxUiUBn>2x^-0ed~a(kkiBZuF(Qe*%9K!CO2#YWX9WA0$+?*)?B6 zO&n~t)`93uNe7L#iU;%#FKM(@29SoR5(md>v};%zO`I0hXe-9hsw%Cd(N>&qfCcTg*CGnFl`!TNp)hO_)j+i-@RI zUu9a6SP3k}LG&J&1fA_9cLuW+(4H%~4+-?&>bLNeJh&{}G0_phN6jcao0r>w#r|5o z4*XM@i6lM*-gj$(Swikx;7gHXj>o2*)_T2L@@5hkXzQx#{!Ykgqn?ZeT6YAPk>v)- zpO=L@^U7d~-!qfYXTsN{L-gMIT0mE#LO|;>U=4}nA4u#5c8Y`dpctx3?ga3NHAvyfTEpLYOYBB#Pf4%FysS{1KfuV6ufN zbg76`cm2^Ns8BO?J)C9?LJtP(AF4_E7$U!zn@Bw(dcRODiD*^W7Eqg{pGgb@hLA~C zzmtKnP*IPaToX(;OX(x2so1-kV#pP)^+r*M1Pgb0qbPisj7|XUD4rnmIK3uTiycL$ z7O)onAEU4pDfcAT=`QO$jm#>A72EeIh`!|a{VACby}sKZ_%=CS-)&lxX|BE-S(3#X z54pbPe{`&>vQo*gO%H$;`d0_397Xi`q^p{;6y%Wnvi>}!KgT7sGt|BYxQd>V-@!Tg zsc)EqlCw2)ETE#ZJVcOOU}u#ObI|ol)w4BkFhi(0IK-?o%&keAVQx*@3`t&lSAlMM+C(lZ^kumbKdJ_!nqaQ9U2=!Lv74Ud zV0k{IpKV$U>Ksb6|X{#-P>u}JY~c55PQ(@!o{0Cb zW6;P#Z4HhUs;%}NJ)W4yJ0el1o@K8i>@yx(b&j@r(=a!MCaRTQVWwVbRTyn0)AblA zL`g0IU7lsaR<~UZY=^dpYy(%Ih_-=lywayGZ8*v+deat} zEzwqOODRG(sj#5?+ElWZzeCuQnvUg~I@)egmB`eA!6mo-LYiTE?XiR3KAMqIht-?y ze1R&RVly~vp7RCckSVt91N4GS59FNsvwB%TiKra^%%`Hd_8d3$XHc4edkh2RBn>j3 z)u-9#0kBNKZJCzZDx7NqZhIXt65%He!iOVEDq0FRIywQjEurFUTIGjHlmd%w4HTm# zRa+Qqdsy9xOAr;gY`4!k6>EaAtgoKYSTpPNg#9XJAEs%CySSxuKx5H(e+N8}wYZgY zfH7Lkzrg%Gi;ue<$nh}0fH|MFxX?L(C8*Bjb%1czV&{M)D8yAj&mjJKfSHeX1}`O5 zOR20$EuDjOmZ>H%bNTEbu5!pajShMbiIL?&qR=7hGFh{oLs>$xQT-P9x);3fGKbZm z*l{{gz5UNw`fk|~ZwMW(0Ii2hsx>PMQ-yzttIhi;DP4D#SL;eK2Hjy9QltP(Uvh_m zgUXR%QzO?;e0Q;nn7nV5;wQy)w&4yaYT`iOk1k;qLFr!xA3| zj?olS?MI5f1U^-d4^UE_MCXP;U9m}nVtj+L*MjZv(R5vGQ=`rUfh*MLHB3Z}pkJM% zGUyBYVz8rK`PQP^LI6YIA0+c2*)7rX@E`Mj8|-x>B=bb_e&B93{tqOpX-i)%O@DMU zQmr^q=`h%XnsCS-9wo=HH~w=51B`fpjJc>hcb7Rv8r3 z<#XUuWl&I;AAs+aVQT0a1dNqaQ^fj%CDjM*(_8f}>P=VUs`sH5R@GHDu6=SnS{K@V za-2@?llyH3F*OleHJdSMvy+<#&1OoR<%t;SX4XrjFw)Hk7u!^uQ8&@%NFr0PB{I#O8wO)L(~&LFO4Zbn16#1bWQm9)*5U__bECGzcqWwuAT#R|BFI$S0{GhVHT zSyvbFYp<+l)#lN~@l=*0bS(g?6S>CIrN+~>6VQQ}aCLtIg*G;UQU@loz7HL&m)P|z zwd_BLhl1mL;#kcpqyBliy0);7j`+AH-Xpbtvbehc~}meaJlKB1!r}P zy$EiLK2QgjQzD}-`WpBW7WpT|PQA(-SdX({Z1m491SRf4K__XxxvDPHx-Kwk1VyX> zihfdt5p>H0(&>O&U>HHST0p)sjG!Av(5<^NjG)_iV5~QSq?N)lf^M?_y(&*5=$WGt zByEk3pxa`K7pjA;lxPIqRs%PPf87Zu1MJyP4`lOKW`9*(Sd#&E+X5)6$pE_@1CGSn zUQez9L3K~m_PRYrokwXP+w1l+@T~gXLp9l6w{HQY$NY&w^e|n0!^$nQhSjw?MXq6W zwGku8O0Aou>ls$Je4ECwimhSQmAUjl335j1;{J}FE-pVoD6qF>RBp_wqobwFkp%TS zQrBsUxT>^4;U}b^gksZC=2c|?{ljs$pOxuFra90M3^l-vB6khYQ<=#m)&r%=l#qB9 z_@gpQ?J>GjtV?`V){yB6w4_(D_`Rl61sMpjIF}z(X#+~!fTH8jHKqeRR({Oms5|D` zU5^EbqwYI^ZE!>_FmTlUcffthz)|;ifPX0iM?KPk1ZCi;M<<|A893@O0T}1bbxY{? z4cqT*`lXxd+bC3Xd#J$>d)x|aR-d!cfA!;)P$wr-{qq@t6DkW#NuiZarg|I%_A3)6 z@i1_&T9whO^xxwR;9qKF4d9e%$h79@R+cK8tpPM-X7dc7VSN?J02(vZkz$G7IM=3# zFpZnq)I?JFD5aQ0lSr%y&C{GO8MjB`t{GHqg&EY1F@w75Kv5>IldT8W38PG1-KL<& zu6htuUTvG5?*#2BK)v96NG^zwT;P(N;RLU@1g+t33l5JEStlaHT_V&P z>5g(TsR)gc>b_o(w*ifm188Cmj&j-KgA1e7!ZMfqanPH2VQ#Y3`IU0uu4_-V+j1B{wEc8LE7w(`5H z-c>*ru3FGQEjxVGO7bo%4+>&@OA@`y%JD;4Yq*z{2iai_4@?lF zw$?L=Tn(O3plsq~Qkp`V7V1)K_2c2m&LmZA8ou6{WX;P7PT-R9Bqr19dn~Dgf$Mxy z`RO8col9yWsm3&|SEwtY`N8l+XH1UrkQ$?aGRP%0CJd>ME$`knYH^j{Rix}S>OqPA zHR?gA(7i^z-091T?{((hqwE)U*bA;%pWz=hfJ_`l&pP!P1YD^M;_0&sSffl;$LULa z=^MO4E6&JrlRDM*mxX)1A-7C=$P6Xi)F^>WwTGzO7HEVwQUK<0a?^o{$~;eEJs{%M zUL_&KJ<1Tb`|Sp{;ibkLu+lL`n>`?C%W2{XdBg!MNYpT#S9H}TP+Tm zW38t~Kd+G%MOR%$-Q*ksO3dC1`iL&MVRY|x)zwsGoct3>cAb6BDOe?UF~b;N&FLb^ zG<($);5w1)BE}K!Rpo$IAlh|abuVyKnd?Zr4m_?5jjmxHxu&f$b4jcM<|wm_#B;!( zyph8O=;ZOyUFS6)Q>=69T4x8fvtt;>e*d z?9AxM`x7zyw-6D3*V*@kGRZfZ;f(yU03@~R?0*%|U5#&qrCG6 z?>hTq1O5M~cH1>z68)LM`ah>k8i~IFe^rLLx&L>-8_Ezo2D}VBFIF_vbtu_xDwB_x zp?F1Dd{x^{mCpgaM_WeO`>g6GKNlRVOJFj{fgJ!DBpVGdFf;H*V6id~ANU90H_Bj; zgBb6?uav8Bg&j(S4r=Qp*tN4p|JZ+TGJY7WNBrMuxA# zO!Zn6{{#4&cD6FwKGtYMGFr-|wjrMY+6;tzgH^YxpLa)D_=?lYgf259GN_+-gu1@~ z`t%7%Fb_D+&}u+sW&TJ4wGOot^K&Ft00UHV%5g>zhev4Tmd8j(v;mrnHpkYDIC+C$ zm2pk6MBQqTb{Lc4R)YcM+*5ImTh5;FKOE!UOW=J!MuEMs;QE$r^(q>^^K{Xj2Tdcl z9QdD*QG-d|cVv{F+su8kPU#ii7iCgO7vjY3T?h8cxO>-uNzfw4z3adv#F6$Mud9*R zJoZQep|pF~!GIj4-MbD3R8`u&>tH~>quy_)Ta)d5hy;X5X#rNx$(X8` zw=geXN$ewe;h>W za{J7hi+EUwH)~>4&I()Ow?bSoFxuo^5Gi#A){M|NDn$E%^&*IaAkwC;iZ&@1qSLBy zq{dw!QfnWK*4TmGotbPF@HS5ezI~zxRByNVOJ|?P_avwY8eF_)2-o zq+;8Fu44K56JSysnW~~O)ed4CgLmc%J>KL+d)=a@e>4-Kn2li4sv5l?$dgc+>Qp!T zqL?+R)6(pdLR_Jhf=P`x`K_93u}HVWsUkKh;DjR`P84QEpjnjISYdt+G>g_5CCsKk^C%0$z@)7S zw1~1fSeR9T)loYAg}FYkI;wE)V{y`!23BK+o&dA}PFWaO-6VqP0Vegvz?vv!DbEl_ zfuP2f23HTaW8{M^`97k>O}qIc(89lYClk}%->1;2Dnd| zmq|Pg{E>*7mcamOe?;z6;A3UJB5?uu9)6*G%ID;a<%GDFT0OA0EIjoGWMR3ely8A~VLQsc% z6oVL9ZuFE<;BZwaZXy4B;2}|5V}?5cIlJxXub^Mx6PAIa1ukY3OZicmTq6t|Wl5$w zqdEX>xxN@U=CvAi9hi}Z52xJiW2S(aWVko-9v?Fo%p54l^gBuh(*w-Kv*5+p`v4M_ znk5LK42Ktkqtw$9bN%&B;AS5s^hUFg)#-X4bpX^}GY@7q_^9Kc9^~5bY>dz#%7lP~ zdyD!N&C|fE67DS-9_Di}Z%P#B4N}`$&z0?U(;er!$r|Q1?Ph3tonV=Ux$QC!vjNOn z4Rc#V5Ay&R>?Dby{TB5@ETLwA1D!sd>jb=eSXFkyD{HT^QP^7?JlziP47Lf_>(fS!^`I8|{dmedZT2jjj*qY0Nq} z|2$gZCv^k!TSD_n9HoasUB|lLttPgOo`Ri zz#=n#7VQVt@o-Oq`#m@a3~cJ*z5w@$;kt8Rpyvr=AUFDF!nED zC!d7s3-qiyhlchxV!iYtwYix`{#wtn#*C-R2;uvhc{Cj+MX4$FHD3Hw%~|qpn@o z!`uR99c1Pm#R6L@@fb_yx8)=$eFD;%=>5R&y`mR-TTW74Hi?srdl4 z%^&LosX91tnW(?wQ6GODl}38h$4@6S)uTQhv5a3R>Vt8B+8_B;k<9qptP9Rh^hT^l zxEL|Uk@~klN?CX^Jv*Oiv?(nmt2B)kHI8RHHvVa&&)x;nkdJT^dIH_d1dH=5f5LEZ z*IIhR0|x08QFoZ7w_5`4FNLA-dBa?#rcAd=jq{bNBBGPxY|2_&Wc;EKMWred+6})7 zvC>vroH^RX%0>HHI3r#D~H>HO2b(kT?Jp?qY`aJu=C@MS-PBr}}wAn;qyP$m!x zCp_*M%7iz_oR*iw&P9bcp;riqJ+E|cwUe<6b zpFGwu@qOSeS;HyxEzBg1`)3Av{YmT~s06Y}Un?c1b}@f(=`F0vubqI?*Losf$jv$Q z{H^&*G40>s~QQIGwT-Sg7IL=dnFy zGZD z`n6sG^^(D?e(z(x0P~sC1`X{%@eQm-4;b@66DjR5g+Bn_Nofb9C)R^g`Bk`;q89Y` zymkS@Q>e)7DzA0dbKWX&!A!4cM8)Vu6j`ubMHO3EvpZpS(*b6@tc2fEDLnI>%y_pK z)TYA!)O5*gw-?l=wguA+)67n^%?N7gpP1c2ujOzt5OJstN?4tfRK~ zuhgGO0tb*9-K2^U|P zIth_$w|rxyX$=hb9#3co z&u?f1*@;>*+~(QYG)!e$JytR1HqYp%;mXrGC|unp<6c1yd!4pO zF(&03vk^;A>8g8R?TiyqPWC1#=O#}%(;lVC!&1&oo^qzW4(4yjBDb6whs!FMHKlc7 zay4UE?ki{c4qt@Dc9UUeIaNS8IlZKuv`uE6+xw!b{BF}gb9#A{K}k7{%sP~l{cjpB zYT_wp5n{2X7I#BwsqrQ10WIt3zmH{H+PT9_Eenqy2GeK7bZ$9B(!z$i&Ki;|I%X(o zeR!s)v+1`(X{+^gd(eVDrk4YHvsy}-nUCi52~X*1`aQrgvxK0m?+RMfA3#0SU^2Bz ztbWyMx0#Q2^<8aS<)2jfhgnRkg+A&-P;WPwOs$1BN+?z?lxpc^2C;I6jg=3w!!*n4 zxeN6fJwbOfB`u({+%_W5P-hGQ#|=Ttz2G}zGPtp(q$TxM`1Lk|TMv$UD;j#;>;kvV zESN(dEB$&;fjd!k{2U_hDi7z*ef`Wtw39N%jG{GeyP}j|yArBgB)c3{nLG-baSC`* zb~y@jwwN!$e2n$v^|H-mmzB*ZthRDnw6|i1tcQi!ii5HquO|68E`zBj4 zo~$^{k?}GcPqvvW=?=yg{g&Tvr2Q((SWug*q-JJ-nN@&HF?Nlo_?hj%wDlOHnWEV> zMlX1-{1=(k36HTwFL{jp-UioL#ulCZ6~>^b)zYGGtig{k1L&_xQ<*geKNIVp*-aS? ze&#?x9m?Qm&H^T3KItQ5#nOY5KF172WL4%uL%Zae z#DJOqR3?MO$H2QHsOew3~L29hI;azW_fLcw{BU{aKWq+C(Fw%gN>9fM(=eq zjp0PcQL~tnXDv3YolO%0p;mIUwgI;pz3$C4rHW>C9gNJnA7f0J!fgXZIJ0TtndYn) zDLSb)Bc#luY_^%}n9KdL*C_j&=HYfe2Jz2&)2Uq+9*502ooI1b)VlfQ$ZOVzVswR? zb@$wH);FM0046$iF&9kc((WZJA#kI%4so|`Syd^ZuX_dT*XC5~VXxLX)mpt=cD#nV zLrgo>X(vkKSi|dvhdeF&y*g`S>tOXPvZ$l-b#{}o+Ln9$aPgBd5H0e0v9)uWcD1v| zX;Te9Oq+AAEIa~n#>Yva)uvS8JwoTGrYnN8sXgnbDmvafS05Ce%&rDxg&FuK=UTW_ zXLkkFQK-S^NUEdRLxBOoNiCeOJkyxH2+Z8--0JwX#hA&#Nv)i3{L+6?`dal#t(|Y( z(hoxTzyVU=e$e*+Uj#!ITzgY$RN)<|KiuYoSJRyQQ{hF!pJBkbfzqPZ5h5` z=ke+fNJeKo8I|CqC0(tI&Ui8^A%v7%87nK&fchmk5nBKDQU7(E zdEW*nLhCILHJ_+IzeaE(w9fh{_?mxxa3Zwc_EF!0`cm?L*TXEpvleU&BJFqcTnS&_ z+i|Y%ESbOC(8cIoa=d{N9lhJ$#Vme@OD|{jq*>~R&w?V}E<4AsT|MSEt}@$swmR7X z)B?Tuli)Px**Y#_2?}45L_DZbY8xrqe)}xa&DXKJE|u5?-twGZiKwbjNKM;wTIw@y z&x?=pTP6$7KkLy26@c!lXD$P|gl3B$_UJA?@hfy`rAWQ_w2jp3pXoxYzY{$bsFz@P zOIj*Jpk7i8=#zvB)Jv`du2o!JkBStim)r!bR)#pSq#R&wRqv-P)0kW8$G<5H5AM(2 zrkxnBv5Xr&9`IDLgh;jI1@3r%fEiYvpifCG4du^ZP4PgwP{A40Mj5uS4~4~wQk8E)Ti zvPopFLmBCJd#12#GnfsYDJ(lm2HA@-;wlVFO1 z&TZQ|M`CWgjxd?CPjZ1Xy~`uKrHX5%E(V@s-z8XTC>#<&9)Yed0)d2JjnU4<%EK~a+1;ft`` zicrRMXq0=8g!?wAf}_C_XEf8f>|<45pgX!40|N>XtEK{D=^^w{aGoz%x=UDG7 z`Nk_cU$KY?uryIc718P{ZFGaO@bnU{`sT||YVQcnn=;;MltbTG`YH&nI)|q;_7J56 z&(gTye5Z*n|fovp|<1PP#yP5#cgX(Kvu0YX^pII zz(8&&4s!lu-&iBeT3}U>H#>B(L2d*j7PX_#ikJR zfhh>Lttagpe*@xBkoUNvHd_O6-gsI(eF{&_iQ1jXsATmf;ARIq)O0tf*9Ec94KU`4<_QHun)K2qVql z`_XFio!J;f?ML&u{vw+OEivl)bJF@jUbPF=raJbz)yQfkj^2J#`$DzZj(z#ffP5}8 z>E$<-^7A?SA0iU=UY0t6%iBT2yS;E^5EAyz!jaV$I#)ChVb$;FX_0-)i|*Y*)jlaC zit28mtYrBAC$k2Yk@X(JDoaa51i>*iy)V?XO*5ETuzOXgwM}#H5~}IHpJY&)drwhK z|NSKO(hO1z_DpkMOj0xQVv;uQ%|dB9q%bpaQ*IFooP)A`ZYZHJ@FjXT@w#;?z9jIK z&BT$(J`wmD`!v-P+eYsbYM!EM8w1~lV5)D1GD8C2*-VZy_XWPUnX1Z65By*=`HqI5 zg@?&>x$FnRB(ucj)+$n!5v4PNMDz9{>jKG`pJwhpAxBLVdp;WW78WwBkVhusR;N=9xk!of5=K@p^K!I$ zzInNsYQ#Bp1FukH12r;gn^$mGm{R6m^GbbXjMK4!`7@Rfc%&YrH@<`q1ga`|+sj2H zdn>u)6*>=0b7U(owlF6%$bAZxv~%W#9Hm7vy{CDRj48J~PBwo*>VXZ3(p}&YWR#wN zij|d{oP7!z1wO?X(!YF_zz{gk?J)&;i9&q#Dx&fbdbfJ|(!VKm=&ddVd5#eGDzKQB zgsA!xh|DFg36X3O{}tk$*TNBmOfJ2{-&Nx)TcZVtjJ5v&5eR??e;Edmwe^e;=Y%+S z4n*1uX9yG?;)Jvb6TuT!PnBd=!QUc4UMBNob>Y?SiNQkS>>Ck-&DkB_cE#hD6ROd+JeqpdSQCmB)I_CrTipo5SVw2;0wR&- zkysZ71Ajgj$3-H~JS-9$JQC{=+Pa25iS}e#i$tDJVgQ(HA|%#8il=hT?`lEf6`#Z? z>WuJ7OeZr@BrB{5bc3e6)-+Ld&JxCXM0`EH$M33k`r3EVCcg+7Ugz&sEo z@mrDTVSdj*D(U@SmINYS_n6NG0b-r*=FaTllXwrzJ5dtnL}IWxE)u$L*pfix>pu5M zTp;tkNDTH!+=T7ll+6hY$IXAj_VTgjwfWF#Vg3M>k7=0uE>*%nO=bQ`0`cA?@#g-8 zL^q&gDj7ZOo%=nx>wuvSCVk^s&!lgJQESq?#pEO2{)JywG7HPXt1$K8Sb0VATU|hg zj9G|N$uDlY4OkC%>F=1uiY||ke-_a7tgIGhu^baz852QSJh+Sx&EiHLt{=E!;hLHy zYD+jS!~Dyx2bWo3mI_x+emAfkXHI{_EEDb@!COmLk*i~LLCP?& zo5up9(RIcZC?@47xjDczWiY*)*8_0dob~jlRGMfuS7sH{z5&Gv{0W^`(}^fHMNd1V zAdZ`F2e#56^=gXBObv0RSKp;hqu>azSD7&+P6E$3MYL)ayT#`5TFkfp;CR z{~Pr@U&a~JCW&A5ubF>CoHF#ZAq&u(57qyM8h~!T&p6}tzo7w`di3u=Ep$Djc{qjQ zcg=oL3zbp|8yi}x&AXD%MsmeKkup0-pwJCh(jM2&bj)yfE$d!n3=JyAQ<_lNj>`2k zOWDg$nDT~Uz!1$+B^i_pGXWSUHl*5>r_^IRGu{dnwQfL78)m|j)Ve{4QXZ|O4qq%9 zlxhk{J!AUO&Gig8y(Qlz#fx9kTk10&u`ftDl#Mq}FIkY2Blex>P*u*@T*i40w| ztSq;y&PQmJd7U8|gkGUhW-C)4t^)duZ^jbSkcxrxmhj{1HuQn&giL`=+ojL>7Szl& znT!k;oRlW2aoS|o^wMeXn9M?@T{f~+?;f#HZgO%+KWW)W78REN!jw~co~Ud!i3)X3 zl1}@tN$jn(sQl9;+m@uW>YI>Dr4|IvGO4CKf$?TO_oMn(GVSz_M3R(eNT%;OU)9k{ zi>l6f!n?CPpJdw$Rx~8jue^Yn5^ob!#vk*Q$iDhH1U?bjiJyl-mMhui^Nzw=?#or{ zpC6(x-S3gU=R-O-kJxTLq;s3hn)2ZQX~TB&vF%Y;T{H5{+g5aj*1F1+e&X%g>VtZj z1$tj3@}OSkYV$f;=F_LLnG|lZc%4p7dN-w0`D)^vcMy)|tI2mOn@zMMB9l_Tt)3Uy`9u_cl~A$TeDft94&{+-mk=GGOt+ zeTc#7+b}q95?6~3NP>OYteXSO0-EQffh}fxg#I%rRNHRFVFmX1R_Y7#v# zeT+yx^d+Vs_9YU_oajkxV*&T-;?qcM-An(gTZycLS>g{V{b?(*B~}hrWJ^$uE3#!M zm6UyP!m^0S^nMCtLs{m-b4fD%n{ZF>RopkWobAkY1>|f*iyIqNp(3;RO)cOubIDw- zpE7TuU^sBCGOI}}1oR@e%q6O|liX%ttuhBlJP+s<1({gbM#jDIKd3nK55UdBKI%A| zS_67=EAtr=xYDMp&}QZwTA4p|w zEvZAcwa4+M2~Zv9alC0BnG!h8+Nw_Bc+*Y53T5DU6Xv|>VP)WW6YOt#!s9sWL1D%5 zmw=Xw;`kOk{uaISEy8h@?#+tf7%|E$w&=<3tPe`+@FOR>r2x<)TymmY@bp_6iYcuk z_`%swjJY{G@C4)qc;jY^8j^T=jo&k&yc0@x?z3iLu zKy#t?I(Q_-y>{0TrEnx{BfYNu&hrSqFToaXa;BOAvX@4Klqn0B^+(`UCGf1N*vlZ> z4UA3)#xu~YA5}-9d3;a}xXs2LZ@CrNq)dne;=ScT2AV0W$SxrFH{e-i2xps#y_=DR zI?X5==yrMw(sGS7>qoS#K5l71gRI#DYxDOnUO$^B(RPB@&*sHs^n!{ky@5&nY=(`^ ztNngHBJ%-H<4ZSGT5Sf_rkBbMXfAzh{vMEvX04`J`j8&dGfc6shwQdi55?A}tos#1 zz!{;4)x%0Wh#q<>WnC^~e;0Q&8~AZUboTW`oG#T=!-nV$Xrl7Xk%*I%5TBA&ID~;f zBz;t8uXzi8ZNSO?)C)KpCW6X5*|{zQl`v#oTQJKlTB~X_TL>*%sxX?&lZ;=Z+0q;6 zX#>uNPXD7<2ApxwH1^|7&MZ6N##ZHaz>VvObs1h$J4{(vQ#aahqd`;DNhvc{)9yCK z8*-Yt^(K=-Bb4%$&SvdxisOK018fShHIIlb^ZxoEvAhlC{GOKO<-CE|>SI_E8#b4F zqe>ZA=9~4aGveGmjBPN`Uzx2W<^r=c{5PqUdyL#2K&dhhInJ$V0Hs#UKWZ6CcUwxZ zxj1!~dn002A6rUjkafP^gQI3dTUQ8W$E3F>gU$Uz(BvB7s;Gt zK1ANcgIkN}DZ5g=0$NLBx4s7aO&K(H>-)f)kjkz^YiUe(wB3dS*?8c+xuCB){*zTp zt~Dd8mRt?N&YV?TaU;+w*}|!<|GxAQLFfijxar*<7>`KdaT=W%gX6|}dt}@fh1w(I z%8A&rdt_{nG%F|cOn_czk@L=tExFDjXAh4@Fx|SZP9LGB_VjqU1Nro2Y|yv(vaNh` zBTySzl<>2k0oDTaU~KxmB&GmEl{rpAi2c3DY%%dhL75a*G)qx-~6LZMP5!bsEUt%zVUVbmVqlO7H=@ATef)IYr+Ek^y* z`=*KN$JEs@zod2c)(nGtnuFBIdeT(Ki_Jj|Gwy4XuS&h`Fn8J$38%NDos(>8s$^P< z<>8pEl?|y$1tL8`=fQdXg_vDHaQ6^JAhI4QXc$4XP>q~L48}b|&T9f8^L>i@-gp(} zEy75=!UjUrTtxWs5OqZFupV!>-}WrX3lnv7x*7Y3tG*6eke4q^AJaTqM;{^0e$al3 zFfhf|$r1MhKxaMYzS2u4%msNFZ9sp?KJ=EhB$z@NSzsmAIGfgM(F3`ZejQyOen zPC znc``BT4A!%h@l}=kD4KF6xHXOp?pt>`znVeV`@`iqa3(PhGQ4)G}-Zc;5W%M*&;jT zv&+Gv?sbg!9IB+B)5cIw(%)Cc?@>{$^v6bIcaTk_iw{C$#&ARD73kSn1i6oZcbqVV zBdJx6O7@jg)WlrD$SP@N%WnElH7M3J?}dX{UjUxBdedMNp0w8Zs?Nl$duqVjB#(qAWsM#4$s? zVN+b6+P~MR5#+93fUa&xkh`u01}TFecR_g9XvqUX?joq{nyw6j+*Jy!^aQ!T1VQdE zfwC{iT^lIAS#=TQuG@jFu1^+ODag)>OiPRgRXYz$0*NC-+(y+J$FiIw%3Zrd*lwW& zz}&VAr{49jEU%3xl3j0s`6sbL(dD*bu$*1rT;2gv#iZp*cf!D(95qouO0INgWgvsq zC|&;$vDc!gy%tdUCu854*4sepP;I!X+gzzycIK;#gFC%z&za0_pl&y%bF5P8Tdw3| z^;yNCMddp}E^Cj;VnX6GJ`g!2a#^T7@lXyYJ9eepTUT?l7ky71d}I&0cOQUGTFnch z?TxOO#GS;UJDbFfbN=f|=+0|ETp2gs(cV%byK_7+Iu4^b?+NHmZ1T>ziO~E>LuJ*= ztHE*4Zjs?qrn4+tHtC`=M6|aFUVj{X;6|>UUK?1=-yv#`2QaYTyyvpKcPg{YC@C?N z2!|i|4DF`-opAV}kN7Q!d*kLiABjP9dMCzl=M!<$oR58uzXI`Ix~tN?T14i|`UHU| z=Xe^utB2#ml9Hv;!2!< zdNRL@CG}mBsD!g;jf68ypL`8%k_ZsaZbrY`UMWU6yJ@vM!xPSKrm@{RK+YNF31>H~ z>>lh1XLkvi>2?r%`nduK9kT)`jCPU=L&@ppXO*C^Z^? z;vrih_>0EBr&JY0xU@9GmX2^s2_0BrPW~&d0Cu0?cd-?~%{Y$ky-+OOjTP?Rjzms* z64^~4+5L$88U3*kLfoh-uJgMaK z2-Sbz?NYtHl;7W4s$W6%ZlCI#G}vvLUlXC^(0W6$w?BpL+W!+ z)Z|FsYg2oP?=wT3ddFs348>w&UT@B#H9-g4Sy{CXzJoW8;os6EX$zB?( zzB_cMMfT>X`u5@hdv%RZ>f8G@@VOdomalEXuS0+s&b;=Zzz~1&PQRZqA2Z24x3@7mn@E9`% zonT@)6JeFzNSM`|PkG<@_T+9}W3z*$M0?-s7X7?`u^u=j0yZ=t$c8}Tpe z%WM~q+4p9+%pDnwjX8OLh~!i$kxipHt8Q}az;%?#WtxZlGmqrO~(37vO{WuTBE&G zWbDx)Zj(EQ@%x?_%SlO_;0(d+a#9%DzkpYpYW1p$$o0U_z>my{BZ(`V={N_G|G^CG zIqu-d3=dTVsx84}lpG8}9wc}koQlU?=Xu=0au9c*9Zg7g-X-nS&`vY^In-BKmn;;_ z4xR!|N-H%Gw}RQh9{^%aC$$8Bx!sj!e-qp4P=eze(#k#Oa)lmRp`1IBrd3X$)RATm z@DeG94$Xvodi~h_MvQjDITJHE$?uDi<)n0Ge|f9@N{rJxi^cbqcF0{Qs_cFxWQK zPadw;4AN(a%!A{mJMCO1ox`muX&$%0v2VMf%fkzS1;l-Aiguns3E7{Uc2)S*hUjo9 zpxdUhKSvqb5FOqMAYR=_-%mwTJIlOS8dxh$>4{ti9r-V^)%Q_zU(fVjWE+^mmpt5?!w0BV$b0*&YE^EK z$=UpM1u!@uleY-z?X%|lu8Dy$45D&=bNBtT=KJQ}`)3C@Sra(I9}}k3?K0*&tCeSp z*dR0qG4HxT;7q1}-Jo}tcikZI5O&~RH|Xuaxqq=>Kv3=Ng@OT@{)Ga}$GcE44Z2P! z&#^D1tlg+Coa#37oTa!G2h#_`SYj!w~n9lO=E}vh|J)+K<-?q?^jjc&^534bArx0m!SbdJ<1?1(uk22tp_TEPs zh$HR2kFsiFeH~N>wRbX2QdG(R3Z~NjS1^_Kzk;cB5+X-k z(gSn{z4^@4Q#!1+Pn-HmH&ENZ8apn%-iq6;?8w?F{knlKXF!pI_RNgNlNL{Kf~E=m z1d<6T=0MQc$B_G>shnpnBeXdilsq3s=FWWF9R4w}rn&}_xNI)iKv$AEznL5Mlhfy^ zZn5fK0JjXsb$C!5$pmIJXQo=i7K+{j%XF0a;;9x$_KqDmXDor!6q4_9Bj$F&B3Uqe1hXk} zitQiAzGgA!txv%)cOER~ccP}K;6tgiolhkJMtt~P;7wj!@VS~lMCNDUCo|3Y!lmLI zNpqYdmCT$O&KGw0%X^@C*2xi?9{;^990+C#axsj&E_^+PBO1p2|^Tk^6EWaa=f%#4=KS&!)> zH-cGdm`>~?wCZ{%a67|z+p9ofRKy}dZT z7Ysd$k87Mq#{hbfri{)amV;QF0L5}BzOKX>B}6RejHBLv(=Ih8FWIE58RRJsn$X%S$%V-0hxy(Y9! z9DHhVo_l&dJy%*qWDAKI;_9($R3ibI9UZJ1Z*67-36)q?<-S#m)JVuCOr{=sI5u1v z4EWe4UE|Z~Q|Yur$qACnnRpp&^Bdlh)eEOI8wIwUakdhAnVmh`9^1rgM?NysdTIh-UC zN_xhzhZc9|D)Ta#wm>Uou++Qz0zEyg9Mb(!xyL#%?!;VAD|gSP!c0ASmqdKaeVC$# zmyF> zQ?y(}H;d@yBC6R;Z`%{^*?__RUWDlcH~UNjj!+JUXeiL@jCdxDoGmhcbW$4*|ciQEn53FWXklTwc^_tk>!TTj1?kI#W=h z0!zy7TVy`?*F8)+U10PBQ%eddHeK0q)v8N!13p>kw9F1v`Mths6ex6pi5&_|$N2W4 zzCJPtGOa_XV@SBJd7ZG9xKyDEf-bII2;CMsy|dMlS^-8|$){vnVHxTLtL@8Ubt@@P z3Ylx^Fxe**-@YKJZ?-6fLMGE>Rbuk0L%K^SNK8qMx2@CColrqsU+C~~j4BzD8GcWe zXO2vonXY-_PNOKOR6kD@i>fZoQ{}8aW`$WrBD;oZnLW@PFOI*q%CG`6JT#Q9bL>dn zL8zD9iz>wr4T(tQcsu%vQsTkgOGQ`J=gmsN6LMZa=lGSht@2;q5^htQhsxR-fqVG>Esw4XsI`?Y@#5~k0n=yt$u2E}vt?ht38m6t(_f! z*Gvx4-W#z+)wf>M!5fZ;y2*eQxsDa_F0vCeoX+wZRq0X#6i)NLOi3Qi(cW8wFM~H627ux{ffl;HG?Cu=(4S+7+hD3^}0xCi$w;b zAto*oTjIUG+&Ca3^J$B7o@l(-uo7ISNVI*P%s3Lasz*m4o>FohNsN%4Ym^YlG&d@w`(ZA__bm!7EP8La3SS%zCiK(EMU&Y7yneU3iF>mX}C^nVCgc zE58dn7$zWJf1U&in?)p2km9k%WEA0mS6@V(^4cnyMvi%T)G;;xL_&*e^X+}t>=1R$ zj#j2NhWp{7lZUd5tctrYkYr1?wUEr z_felEpDv4iH{eya0xwWNw)3A1yGmpRWkFwIo0I3(w%Z<-sVFSEnD-}ye0Nr=Q9(MM zDkBT`P>hHPzIKg;)rBPzZ_!W?b$C^l!`F&Bd~G?kL|4b1f9gj3%^D|u=nqwu>d95z zDC-*_mDB5X zGwLr{u|dXPG-q3-`ILTTdutn62Xg0_SPNm3t7Tjjw+~LM{DncDYtGet;?_^3{^}PE z%?rr+?v!66x`L_cuc%mK#4K7wBkZ%p3~HynSe6RBc);7!*7Y$ivu>=dcM-pKs;M7As%P(HKpJY`Pf-osFk_b-cKhDQUqstQoL#Op z_I)3haQC^kEJ2fmyTpquG3@;B*;CX#{Lb0y+XYo~OR(UVpmmd9*`K%cMHxH7RvL^? ziggE@w${G471|I}P+EEdCu(zPXlWY_Etg-sB<3x=8VQ@)=t`o4WgxPWkTN@J+tW!g zg++vCpcSUiF0sg1O?MS@EGWEk8^L1ByG4(GSXV?he^ONUScC$^|4YYreL3Fu|Hz!E z10uVDjviuF3=K&xv)W}`vdWL_Gpw4~XZYq7p=!N9cAUQVvTKT=$CMZi5gE3=JM&$< z?#R3(|tc-}_GLgFLWclOG$Y}z9yJMZg^%Wg6(C1QdbBVu+Wmn?&- zxzWNq+47IfFphkG3>CI9HGDJne1vMn9x-nB}@-T;w#ZmQR8;N4ktO zx*2iT0>mX^M67FAOkIUk?yGf$?#c>2>-&5{F1p=naH-F8=oKRz*?%KH&i#K42fnxq z4hLhlACnWpk7`_vGR#-F}!tgpNMzZ*y;rbjYYahWkcy>0HZ8bG-P#nN*}2 z4iGE8bl15vE(tlj%H<+o$hwFbPn5BzB);ppV{w(tDT!+VoRs(!<%Y3bL{8pgl@>X9 z_X0^IM&ZVnEG%?*Lg@CEY3@0E%<%(a)$vKpDzS#|*){!%{xWNGcCF=w2||_czp;#Y z@hZA}-~`@AspyneM>7_OB$vjR$T>-@jI@mRFLw~|@|n{)nbT=WbUG3;z`EW?796oF zBO9gsjVfpIu_7jh_)B^>B4oRfC8(LA>7@&XX3+&h^NSY@++E`?7+OXb46Q8N6&4Jw zEACnRwNjxQFWSVKkmu@cE8^@D?sCPIcAm>4ddoIZKEg;H?BIXpbF$ zwQ?_3Xepl%agjuy3vd7It$dSWZ1xhHOTL&viB-#m=mab6aKBfq;ibB!krrJGq%;3T zo3JzR-8<8dFq;28`>;oYY^5sXb1vfEb4~WcG1a_)Q#mqMRJpVj3j#MF(1 z#2mKT0Eype7PKb>cJZyNU9lpLaX17j8eI31$2QawqLH;SkdY(DU)#$x@fS8tBO|ht ziFJ>8LHr z1Nc6N>(=d}Zq2*Z70x=unJ%Fa;)z~k>u6UO)`8Tif6iz_S=T&?v9o9FvC)mo`ADJS z)ZbMy^X6X9*CN-u+=CP^JaqF91Lc?=t~eTKFI^~zu&rt%Nl!(RURF44oqETLP2t3M zu#1ipB5_4mV`8QeSNQR6bgASk_t)m5go{H>VsutdibS1c-_t8@GCb#sy?XB3T4YNR zJ0V3bYg9b^%W(CW>8ZrF;QF~8Qsg`*a>C#eM1>Wvb+DyyBZ7CT7PJ1Z;zqKnz8rqd zN%CB`suppPsA?h`irAsJdkV{)8}wyoHDdhRy_iz-e{ISyi|r`7?TH4RsEb;siwQj5 zETax}Nj)~+MnaCa6saSGCY4A1xF#u4V&)Cog4BlYOjL|FZdNSi!4x^`Rg)ws*f(6{*UYK7e|oRegr9u zMvyjsuy5j8+RH;bM7-7u1|1cLJ4LYGgr?{cxsQb_8Xi&4vb$D{ zP8E(G+$#V&Nx0OX|Hnd}lf;-6M!Y+N#N03At|ltnL6P9QY3%X3>xG`H%eq1l|BtNS ze=US?q<$%{X;E89_k#x~iEb4x_h5VzQ6Xh>tuVTR>Rs(1&Kuu5`B-hccetFqlW#{{wVsQyI7j{L*=`UUXipf3a0J@U6OG)T;ecLOYX5$c?S=BI{pWXJ}%jQ~}jgLgn>V z?#(Eil}8;xGiHlegzFhCbq@wpyghgHVqxSe-2bt{_Nc|i)V6Lw634h9%LL~Ab{D%A zlfKqJ+|c5CSTz22tmt-~V(Tal`FHGaZ;P@xW^4`D^*9g2nj_N=1B@T&#B=vyVv)t06e*LEs1|iu5^veEn{vxXZ+Lq(5+%{HEW#Fc8oiB;|@p4TC#y z8@6E^ZDXb}HhPT>W5?(9$uVeR+5{C@yNO0wO@#6n{I zf95;#<;#~Z&p)%THFIe3mI@DK2dvmQuH)s6j8tl%Jz%|{+9r=(n#TnKEh>X(>t!8v z8O^_nkEO>*Y*o3j7T>HE)f)4S;|=q)jQ0#Bht#>VE4Nf~=v%|qD=Imh#Y4-K9Qytc zB(4wr91r4?A~n<)LLyC~U)JbI%cA@vNu3#0A8CwidC?MEkFB{EVrwfe%j@DTVzo!A zqxkv?a)kJHnQxU5->CJ11*1R0eWT8oEU#GRZYkfWpYe!o4SPmJ393Ep8=)*#(1%7q zkGIN5WrTQERU4^~@Y^mcWWbx`+%pys9avO$Jg^0L)WLXryjQ~OJrYL8Q{y_-*m#?RB8!$k)o?bQxTdb@Y&-2Q|ASkq?G%Jd8UgrzlKEX37nBHHkO2xzir()E zAy$O|w7>X*SWAM4R0&uoTq)9~2)-_0M24JkCnDp{hI5k~A!nF!gq=|>M^q!2a>SiU zk|murrO97RW&WMxOdkb?|NIm(Wj19H>=H0AI(foRC#ar!8S4^bUCq!28spjrx`mhzE- z&k=Hna#YCibw+&Mk=79!o%m5o8726#2^JYu13~Q$;H6a1p0Lw2LMpCU`BfSZlp}vC zWyKYQ7gWQRu+zVlGb&+ED{*zZG)B^1w!_85K?t58$=K_5s3|6k)Q$-j!I9CbnGQF)>L-H5o7jZ8u#)oZB}=25Mz_rUJmf& zwhn|UNH|gs7mf_DUWBJgp_u!0VA*;L#a-;cATxi^ag$}zRJT|Jw;Yikfx8H(Iw&RR zDC7X%B@@rc0xC=aC4x*eShSb%CxVA0fFz3Vk%TTE6XE@nP%UeK-)aPG1tkg>*;>|+ zf;1r%94zS)8Vd*lJ0)l3vGr0=NfP<)6uQ|lB@$eCMIngTsMm-sO)E;irdw9Ynjw<1lyF#xDp?zhz6>vJ1%Xzzn&>i+oWQHg&v*h(sm{Wr)zxR6 zuUcMYYxb-MXP&EwHN{8HTI8c-EnCsr3A}8rSl#kY6RKEi9SD;a;jLEKpqid`Az$uy zW^UniK)?1|t@8*%L^d=-FZEUuBS#jeZ{e$-QkFB6?M!(Hx2E1y<)P{j%rUl@S(b2N zwY*Ard9}962%~P31f(5CFl@9hQW_m=hoT-n>+ z6zyA2toNcN);;^WVe6)(-y_-Vl=b89p4`XZCAnVqw4&~>!(LRm6>L8#Y#9{kKPl`O z^g&80=KaZkXEXWl+(nLEvA%_W7CU48B&5LWSL4&TeA?;F}?&%^q;bjS!l8C#n-U`xjkho0>7v9;OQ+HL#VJpOJ@K_Iu(sjHAMu|2gN z5?V#VGYifLmS#Re7e|RdrNbXXV}Y~p{dp$2dz95w&vfhFy|s8ZzQYc~{5 zMgEX_;RbxyjT?CLxxy~%hiK+q46W}Q)~gzNl_2U%IE0`J&|!7`k~()4e`@HpX{Qd9 z9;`W3@wqwa1J0enJCNamiL85r;3>*2DV)fL8dSIb489eIea37ErER#s_~XPO(l>S~ ze8zhXIBl!-ni-n_>2;6QMw6C2)~KF;JtB}shpCCQ)iKY80EJ-=a>L>1o6J*0ksnbm~TPE zUDl7$z)aZ%D6ECkouYpC>NM~>*x$XXa6ig(YGp%G+&F_2sR*RwNj?4o{1{AZ^sMbwi#q$b?bX-K z)Z@_53P3A+?Jr&fdk6)Fe+qBubFl%6O(ZAq?EPt!ZzD&$nEzcbfIJV6#z5ZQlumNf zjvn6y6~!2Y(b+A9EtD8li|oI>pe)B3U)7x$i;JcEr%e`BCne%Bjb4k~brq_3_7ABL zveY9tZBfFP`1ZbcAQW_o{s$yu*W)>jZCKH_TW5RB^xLf-EAqUnnFTNc(KRi+R?v5%rq8EqE}`>A7Ohe5n3+rDFtu`L4!>uW;Q=|BaGfIz z0Ek>sI?0psBjmV?*Vz;ZP}L@t?L~^ArVL(`%+#rjH{F z17EOo8`;5%b>Iu#mRKqZsE1(M(#zU-T|6@68)~78N*PQkhNOrusKHSTE=E^imn)Ck zU$u2jO;kNxG8)mE&G{ueTDe=QX7gZ(rabn%-HgiHTYA){6X;O-aAFHeN7Fh?+Djc; zMhPuuXg2+j2d0eDy{x=eH1yA*dr-6Kj<*PK8B9`k9g%`4zz|O6*hjN7`1o+~z4B=W zSBxB70RxO7K98<-4D{dxh_JX~_zxL>xsWtm&P zhJLcOYKEReRkk+G5MVW1O3a<9(A*t1{KT(zlQQ3oBz1ee*LL8R+Iz}&@Rn*?ed1Gm zHb2Zo`E4Pam`}(SVK`>1*ia*=BFgHqd+i8%?E$+~#{hdv*Dz>;!mgcAYcpZnt;=-vuk%^=ah()32i#F*LT( z$ms!fi%K5aEAK+CcWsC&HXg_O<5%VV>UGmgX}%O~v|uFsEO=hTXzh7O@%*QC;M3O; zxE|n0(3t81#TXhV&fmFL%xJZu;$L#F8lU&4#(W zvBH?$z20FT8j25reH=5?!ag~aMOd@14K}4$LiWu;T>OE6L$yF zoH8?%Q2Klht~wFZ2is{!kTT&QE-@S3!J~y zvg*3263#NGEXz(GXL5rauwb6mRbZ&#^1IE1?9h=;j1M8Bdn-HZPI1L`CnztgFc`Q! z;)($cyCN>vTTd;pu~!jSq6d@#?@rkm^$+vzw^)5|VGwLKY!P>gQ7L!BjSM#2|HbV< z8@S_^`Y-O5iL^;D;-j+tDr7d~!(DY72EO%Q^tuY<(Kr01VI=*f;p#9rR$;!nD5Ww* zhm*rpKyo-gZ2fJE4Ou`r)CTHoia0L-XZ@`|4SC3b7Hd04`f{V zW`qySv0iDR*>})yzfBhSAyi`mH7-oS-!f}lT)>a!nu0!4<2CwpxmJK3D?JvU7#G zUe(S;I7_4=bE&yb)sae7m`iT&Rb6s>bvx)i^Pzb>QuA3pvh(?Q(Wh$9VO|Fde^$ID zc7H08i&bIMjO~OxQrpnvYnKM`}uFv>p^;>DSso#*74wCi5 zf`JFYR-Eh81H%$Es5!k(7#ENPXeIk8%9@$ZPa`Aw>B_YAqpGm2yv_Pi1IxxFx|pfy z^tAnk9i0r~URCjJscqJ0RDN4w+whAPEF*u$vh?CUt{vf%eL$` z*DIC!@E#q3J%XVIS6XA2!4T21XbB0jnue zG`D$XpbO7TVFt=9%v2fj%|i1R@JP+tKZ6crYBn>AXv#oa(|O&*1Z2?7Y?j$I(Ig?A znrFs8<9yj7>knWeH%pF82 z-X?bDiCvsx1F(8P)G+%i%RtrSMv8P27lzt)&@}Ud!nStsAzuF zK$xntSZ%5{Us})-fs6s`Gt4;O+w+trumf@2Oku`>t;BIv&}QHvF0}x>%aj^D7SJln zqY8+XH|?ctC`4f_OhP;QUSzpR^$G0=@90PMLHI=$D=Dc{D8{>(T8r-hH+KQ&&0UqFkK8wQn)un>sP%&Op$-}t)0AVo zin~x9i@Qp@?4JR%(yki900NTWs8$5vABg~JVpn<>Ds*mFm5(a$Ikic9*qzy}i_oeA zhEYKvhC{n$PAvp1Sd~brqnW4B?&xmkD;8OpjP6eDcD-m>ka+?mOfg%F(Ixor=u&LS z{tCp5Eu|2qRINqN(k3w(0aVYDe+h*V;_}jYl>|P;gzcx6T1y?iQ%m_J5i<_} z%37v-Nt0(HD!)`->c1{++63FQ@={}IuoISUqg6$gi_5)c5?M|x_nJv!IkOCrGRt|^ z|2(l}Zwm3cIZ-S30O=kqKR<^l+m>S2NPg=0X#h@RX9N1}1Y9!#=W=#Ha`uAkhiD9H zu+hKKNLF<&ZG|wu_z(Z}|NiH{`0ih;G!~rEn#kf*hJgF>b{piR?;oLfi(y4Lx%8aIeS(j8(C50F4oH zK`&BOE!EYrp*VR!)I6qvRUY$gw!r=;WoKy_faGFmk+41b>C z6lCv#YkAS(@ALIj0AIhq9}-F;{{Be6>$AG+A$ZV7vmYI}R)29o54NQ6ICe+YbNxQ- z?^M14{{TwxWs2$N22gpYn4y7W2a+7f5ji(d9tWt+p4GTaGqQVWdklXqZ zpkaq0SC|?^#9}pm(0E*S4aWNldY2&ViE(Br#QTyc7!eoP?Y>Yy8if$FCNnybe%O#q z=CcmA`x5;q%S3;o-~K9Emjt1@I)gUXpYL~n1}7~`uQHEGNo1{rjCUfnM8$qD_uG00 zd;_Bf`e)6~s9=CsW4MfsovJ*Z*`gc#%og8PR0i`0ggADTs`y9=bAGC%@vs3(@P139 zL7CXA3Pv9VquRLZC1Y1uZM->-El3v^q(3SYX59gy7=rO6eHi;nRd_s(&8I3po*0*+ zPK<-?d9W>yyWTW*HkHS#<9#|nOQ~Z1RyI1lNq?Qev@HmVTWVW`K@F48_7`m^D`u=? zG}@7PMiL`5kZC9h?YH^qCQuVw)&22p~|5WQYi?Fne{8mf;mWCgk)Qj6)a{20fyB>0pj_>`(m zv?nk(h5{fd&_HR!KmFTG`w>n19B6A3=w^@>)vZe?i8V%Eevsz6acq8ekKaa2b# z*Zlwi5ZgBvq-eph1|P&@Y;B@Bfl9|sWm0Ig;|3bECLyeW5nO6OoC9S54D<)iAwR?=Zc{ zM0{fQC79lOA;e+qzm$!|YDaqE33w-bS9zs(Qdgza_c%NMJ(c06$?hI$Y&X29rXvdT zj1j$|vIjN?XEPT=CsM`C&6ePdTpd1%YJD=SWYq-WvyUPCShS}f`YG<9xn5)^tZ2tZ z%{M%+>z3Y%y#?x1KK3)o%DVi}C$UT$WJfT9O@~Oa&P|_sLJb|QfGjx%Y!SQl!!kZ2 zF%2eQ3ljt$m;eqN-G{ubXhdQMLnKnY1~bN{0c`ce*wc99%rWB1?Cfxu>9ah;sitId_f{a z=KHJYQZhd(Iu;#+IVJds2_{#}D4D%r+y#qEvJDnd$x4EsrNFHc$epYF!3!dP=OJ5* z^UzF~_ThwCG$GvB=PW*sMhB=t=LCaPv<2VSh|jerU{F;+k9IkuC7l5p3|0@pWNKc&qNix5wlBh=s}pKQEeh zmQHvgI$^9;dA9nt>Q^8M2i#4sm9+t7nUN!}SlpkO?<&!Zr`QG^w8AMEt;g_0c|u0! z8%k1OhBr)5bYl1woIJm4zEdQ`xg)NNe7B@hR7?VyCaKPAbRs32ywG8eY)#TEA)5Ka z=L%oplFL^dDJQlWrkrW638q~!H$qwVWc8*)WG3nOGh+UkBks07uVK#{Y*fziBf@^< zNOLJq=&qTtlH(_Y{ltNR#wRq)+!?E?O!hpIebX&!SE0S?IK+GRfG5W2?2VwVy2{Z;( z4A(Zza@3YvoaJaOd%5|?y8>3{*)9-|VzFMT){Kutr;TMR6$6d=u^{a09ake-+$KbZ!-x4bF}S zmcHl?EaKl@{98uaZp?~DXGiafjbg6+-LPY`$=OkI*~B9`n|oL69F}?BjZ0y+{;u(L zEEL==OMBKc_ikJ~bN;!zW%18N-W5AC7kk(E*j)Zy#}k# zk*L*(ifs4Iv%x_d9GV9-aDcA~dEI#T8bfemp2hY3Z=Brnjgu1yr|0KxZ-}OhII*lB zJoGQFe`M-6V3Xvht7cKcI#AvOvr8l@9d( z`JegwUjVJlR|Q&~uXUjRu2X+%l7S^v$J0pn46@6g^ca!H2%BKoN(xG0(K!{pEMhvZ z2fDA=Wopw1&WOeG+qfGD96XC2Hr`~4pUNEjSI5xl`B%qU$Kd>0#{$RAQL-u`VDx!1 z$D7A>pNDVIqB-tjpT_`p`aGHAgR^%HJRC?+wTLh@jw@ISj7GR++=pYMxJ`b&yQCRZxJ7kYDHxdBUqnkf6!3 z0wFBapbg8bOh;H%ezmabMx%3kVU3k#HN3_&K#<2PMD5rWq8cVtC(DR7MKy6$d)3Dk zeBT-t^0AR|4O<3e&`vz561s#l{nN)p-GTtxN?yh2oK8EukaxBbV1~na7FJ+q!5PUEy{DEe6Oji?8(AO|{kQWW)MFV;9E@aVU^@I-` zmsMCeFB{0qruMp=sk`b4FOV_97vv=ad5IN(0_X|=g_ZBE+&g-EVg2^v`qJ%X{99Uw zoqJBEMQ9jx`QG%&9vh}*gaPGTg3<~=INXbZaE!B#v6IP@nAJ%V8yhH;;Pse!U??~O z&YkW^bR@YcoE^#chE0V$Mj7W zEsOkAYp6ZMVhRnn!D10#p1?rFlVdh1` z2`UsT?cmm_5`~lT`+9Zh|3K&iJz-rnh$Iz45iD<#4K_%sa5BlyK01Y*Je590?H5kP z@8gpsc$%u~5}3MAo=SmW(ICJWUI==sh?#<^>Ex*r2$oe{Qdl+!da8*@VCpq_st5w~ zVuWDHAdsp;)J|22-sW0jdiAElHDbpI0(~suIU5@@l$!wh|Q+sx65TRch44 zQPukz_o1#d?rYzNy3z)^ZW4&clzV^J`jy`ao6qk|9m1+&>QMfW?sDW0MRBRQiXKa_ zYm_*aL5SLyAE?Uw67Y1z2$y$7kBJony*Hk8i0=?;bn~ytrV}pjYV2hRHuk3X*#a9X zy)S==;ryZ4VTQ5g;V8qgqggyRRQ6~~!mXoBenX^1@*RFUdGv;j7)g+ZOL?&|in(J@ zvM1XYO-yVzzy>U4sj|DYhYjqJ^btI&M|?*aIvPa6sI5m!e4+HLmaqPQ);0N1(di(MZ4#VY=V(<;L}gtRW!>@Ty)wQjPZBW2lR%eq37p}cd`EmodKJs?yrlJBDX`Rh zM>e|hycgmoQ8d*9U8?s@V-xA7TxdRjKPvGZi5wY%Tsv;>U84@TDggt1LZWOEHGa2l zZXbZ_qB+lFEIBuSd%qckUQV0(CYff50h0w^oAQThR^r}7QK){VkH~hcBdB4Bmm1dN zv{Zc;_AKfeh)4Elf%UO~dT7k!oY}Vc^NVNKr)TwkN8m^4lFUK8)b*aQ=^28%h3)(D zlSzX5t`-gg5)S~k%4ul*gVPGE+XDOHtV(cN`&H>s`H(rc^wh_m_?Q3j%WYJ5?W*>R z7{CIpimjK|!HP~omDW@6eESR!x9{D@@j5|`UgAk3otdxFdUbv7_C6WU8?{hfqhXP-qPu9L`BqfASRCX#wUbuU1u2Wf&B1PAuymNNB70|!P~^~kj_yY zj1VRtf)huRM-fcoA>btVp-0S?gRCG&av$t2Dar2zS)7I+msIx(j`AEstA+(!HrCu; z3@S$TSo^zLzY46!V1TN5C~{bO3I<)56$Q{gmDyKEN$pkjefj-njWb{<<^2BCh74`@ zu^*G#$ZXt=Q%9qHSFDycvo9lGj}rwt0bfZ5zq(p4|A#SEA2-CmG+lK zJ%+u(f$XVB7o)PLxySTA6-^B9lRlC;A{~$;#Upn?HI~T1Z8&qIGS#vY|&c@1&2Bo@{jgNLV@0^y{vY zbe52OdT&|99Jwq8k5xdJQZTDbU#AUd5uje)#Ur0?fOok4hZfkwUy#B=qqe9Nn=%jM>Ve zPeQ7mj?}MCx~cWhe0o&!H{{cm&}er=!pz}2I#L;!>qEfZVRVFkosJY5D)g(&4wTfF zhge_OU6$G)e|qJYJ{jvtPoGQ&g_WkmmI}-qOJ7Wyi^?90x*JU_|U~m4ax+dc!4*=X%3z(R#vY zEU@dVzNf{3nNC!EmkQn^au@<=f2N8X>4U&aAIu-5w+bGOY3bkz{0DkL8XpbzfrMZt z4yF&9?uFE*d(pcT4eVd?0JG2mh<^G{{?k89|8HO4g>deG;cUz}vB|H^%MX^5J5W5p z7Pfexc3>3Ua9aL1I%|`)0}X*T4m3N^Z|T(>&^8aW1ll^#?m)lOS<7i3@E~J*mFJ-M zpvgI{*K|PZJ?Imt@1VZ}{XaTuI{t$Jfd&o+JJA12ujzm`crYZ;(7|vAYD}J>2@4;L z2sCmq+JPE9FwjO1#snHWm^c`=!j73?LtUFxLtF1vh8Z@qZ-&hbn_)AHX4uS>88)+F zhE2iEa931X#Mi7+-QVrcdkMZ-Y8fXH)s$Pn9icm5Q)~fuWbS}XsRi5-xdZMBojzED z{YwXn^AxBL73pMEHYx|v;S3&)NdGf}dV#7Af5099u>1#D^I_0}h zJ#cyj6D2wz`Ze+#P^Vj`Joh1K&wV~jc+n@MP6h8XX!Qm< zp=9FqQ_WNQv;M|eexKC@ss5~=VSb+_4zRQ@u%GCG{rLm>`vfGodte>qdxIzKFTW<^m(q#gNqp_Ef2wpMbT2-N31J1r{j%N$j>$-@m$+a4 ztms~7%A_&B&rqS$Uq1~a|N80DX_RQ`wExT<^(%2Yb(&dD;R!{hPG?R_{mPuqAuO#h zEI4qce5SVwmCsbqK)c@i!}p`qfDi)$*s!`)&Uo+Vu37#VY7nz=rp+T4+k{DFtAK+L zU>4_|#yxyR74+OwmRBmo{Hex0!M)DGoA11XPj!OqEPfJ$iPF0Lt>{fmc~sV|zo{yi zT##^U9Rpq2@?nq*H8UubsC;`1z>JfUBzS49m-d;pkV$Fe#6CGA4P01*8E@}vlS_4- z-;t5{4OC$v7HxA1x3IUk4s93LDV?O@*@wj-sgaF)y!)_4*t@T^&wk?tXbJ@E41i^D zFN!s|H@sIqx(@Gct@9Ho%!n{70%!x_=;ek*zGs92_Tnomshe<)NY{iEp%M2D3zCNu z(Uw)(+mc+h_EK3ouC+J0K1ySL*78;<1A!Y}kFKLiMc1=;1I0d6=Dr_rx#I`-`A|P} zRN=mV!>E6ApZ9dvos{nT2_t`UUx2kFa5{8a+{smtV38#J0c2LFVe#P)#28eu4`eM{V^#5PE>TLwI5d zBJ@Dy0Xx6djyw=U7|UN+r^7J*fy{%wwKel#`9TQZdeDml%jj(zK+q@M7y-!)9I=^) z#siT}93l@U$RY7y>OshtdN6|!>uciy?^%P^XfjDj2_p~2A2gcGPqE32gVbm;5tb$s ztK$#09#rSpdGkF&or+=z&`R&Wd z>)V%8SKzNxS1MPu1yFG54+XD8u84l|gpEY5#IA_Hj$KJ0%)-r`4LqckitIAjJPX7o zVjZt|db$D{)N3crvz~{bZ_h)%haiLRp#Va}O#sDdo^7A)_gJvc9-p8N zVm|k*?;#`n&N~CTZeRh;zY|vL#{mNBv#tMuu`0Lb-;J+5s3!a%(^{TqO#mq%X9*>C zW_Av}Y8J}tEP>3<(yrmxJ590lgGj8hJFy&zLEX;U&aqdu6L{&3pzX}c8B8b=A-A)E z^-8|wcZM+$Pb&OW=-gM%A;(`iS3Cz*70)&GfoHTDt@Zf1)HzC(!V@3GrOsu}*?p*Y znR7XWsrA4kl}9?gPzJ=5_1UaQf(Y41dX=4hr0@uYEj&_s1WA`bp{rEjk-AB1=$MpD zJo`xg5u-}IPGif1)G&2~4O52)K!#c?aXJ4yzUo`+*Z$W-65m>2ZLkw&-z2aW>BS&% zay7ChpL(b?-*9LSnkkD7p|mhfua;KLFPclMo;CA}W?gN;fj?kpR_8uv!8fDgs$aFt zzupPlu*{?V$gE~px4ozx`@4X%tGQpoAcsv<+cqU}U31g?^N{oXC7|>R!oWDn#T3H` z3Ll*xW-0g3k61r`^icC*)~JWu4@)6?Rr_Hd45y1&dgv!a{K-SLhf#}bCZY$3-g8Df z1AeuKst*ILYQkR!Ja|sb5??fAexv*wXuNz6Hy+mADRx9Mzu|kBb@Sou!}8%x7PQjC zP)WQET))|GeP>2D#Ws{A;@sD7o>+5d;ELd{88OvG8lN|S<0ub!R=_h4!x`aoGvC9$ zhn*3N<@a%*4?Z_z(CpNqpL5~u3y|XN3$csHU+iK5C%ze92I~6ax#+(rwHQyR%6~C* zQM^>>VgzB>K+GZbPA^4JZ^g+yT6z>(D?M6y6f#smVS1?!la|TE zs6hl!oZO?uM|-_g5j=Xm6h?8n{)CoGvWLC2Tv~DUTVIf`_e(2f20RiduQVC>!<+C( zQtu=q|1fNcNCKMa^Nzx62KF>4_ppi z)`fIAf-nmy{#ffV^#I#vX-eXcl^z3P39*isJ)T!Py)|N%9_uZn(qlD#*jan5@fc)i zfWj=K4io?51{0%@2%tEn$EuH^P;i(4nvy=Wso-IR-+9N4^Jg(qUu<#1H^2L7E&7)D z3SG4p+e_%)N(Vtgi;kO?GdQfb&7)gzfYefZNynhMQNE@661=dNvB;hfe3FSB+Y~U0LtjR(ThJDf00%=Innz)#mMTkQXqCEg?5JxKAO+NrS_&<* z)}n-P(hNS9_?TH%v8BY4`?_6^;#6WOjYDEo8XVo%^>@EQ6JPQ#cfCg(N6_?Le{;|v zO5*DXh@AmZ-}NsTu}mqCRJ$FF%9WpAfha$}lH;-3xvPzC%hjN|E0oDq@FO!r3lk7Chm5E7ZgK1yZ_SOo6};(uD}2*A_f`ad(1XO61!EG) zut0Ej3LR@kd_56BX>hyFI`ZA%IFU5f0I@Qyy0hk*r z@MMX?cz(8HD9i&|!!eu-d{hcy58>r$;X$B=#0`v2mlKFE~00A)ThqksB>@$L_+|+mBiv@2d|kY{I&X(7~0tLxu%-IKfdL437TB`(bT{ zF|o@_2g%_MZbmzR0uJ}p2GO3^aMbL<&D4ii<~GwooDM(e9kVnTRSyM6|GQt0ZZo!& zq#BLYp1*$^IGSvP`5ZnMccK}@pshbT$ZXvW-W;iQ z1mhtk=%P@x&nnFDM@kLmMt!`mRyyhETDzHEr(sIMGI`(p>hyH3WilU@!tKfN;rFm9 zSUh_gC{g3M-oGPT0be#{;9DHQd|`3qzhQ|ZZTYY`+*ie&l&Xrf|Nl}f;$WbbSYLAx zRlNy|`D0kj9d-S0U^TQ1asC}=u_*#pLyW(X9kJ%<9~_Q9jv5? z>#5;@>htf1xEc1o)r3Y3rs6<&#`TTOw3`Lk4Ev>gH>1Bt4Wj@Z_m#M#p8vN=ezTmv za%pORV3uO1ENgw31giBl`gpBQqYoe4eG(ts{nDbH`}-(bGR4F?TdTj*qNVrk){FOY zp1Np}I$Nf{%cA|&liw`ouT!+*Q&2U-V{#W8i&qsczI_p$mA5a(E^*X+sc;Fs4}Gwa zF|~2Ye~AMOKb{!I_%DSn=~45g2*MmSCqL+UvNPUcu<}75RuH>+yrV(ArXnvm8ONL)fszuAwu6bb9XL_%^PrErl6b-K)k$20D=|e^ zO>&P3>KRIw!V?Wr>Y2YCV2(P66EBTC&c&kRFJ z##CL&vSmc}MJ$g-t`)>Yav<<(PZ!Sj+E?Lx{XFgKLi7S2nG1P5XtAF2h4Y5R z>VV8|$8~jNE%uyGZeo-?pCO~n`P_L3ngh8QD)90b3|hlJNl8(Y=hNqnMT|HNDGgF% z5d&da#6ZnC@5A+s#=0N_!YgL_lEV2GQ*E91a2DEg!AJ3pbwOs0>D13R&2(Z+rwL>u z9fXZ^d>1m^bQq9yqGme23km8caUsQYQh;~Uq3)PY^g{fCk)J5ji38b42VtgzAIr+^ z!RfWigZqH(uY3-RAGmG`2LjL`iKBBrPj1ggZE$ZLpJ+e&us|4v@Tn7UGp!ApyM60|4kcuKvP6TsRo>iUtS0TBe7|Dsb?R4kF)w zbTDzK_r5?CKbT^C3h}6Zi9>;7vdbZJtS&ENCOk3*2lcT+#(@W`vsga*A7*}MWC#S! z!x<u#Nl_?jJpcV~D$tosZyp(w*I~0qsQZd<^J>;~eSCk?avL${%g>qleN%tOR!Ay08TU2hZ`NsmxJqAsL^S5P4&%$P6KY4otqPwV20J(Uv2J zb4OsznPbIccogxlyBp{;94j4DH|o$*=~(#~X57mt8XZwNRz0R(ZU9sTYn~a6>u6_q zmi035b%iqo2KUNgm)C-o796}%IUG9zPO&5Yqj2t$B94^@U)u)(q#my7s;_HV^g(dz;&P7-!cCu?KVYq2^mpe)=!B&zo5}j1pj4e-C^` zHz>dSVcs*5gktiC>xYNlL{V~2%^ah!Y=?!r2tLAdMl6>9^@EsBM9CQM{NA1ChPlnB zAWC(N92x8?0@aHg=DIO=)kKZ)x2tlLOzLj&*yh9uc>lzS@wZAGx*U7sj(w=Pp&#?o zr5_J9hu~wI_`Y5@wR%Sl>o9lL=>Js49p{-Qoeib&z8ohNYkl5+JR<#RK1%&|Q7S!@!$TKs3CC>H=frSGHlB#Y;TAY8pyOEZ;VG+8wBWf^=Cj6k<@1kwU9KJb*UP zNI}m0MyF&T$dfXH1Axf_Obd!M2nxKZud}tVFi@dtD+6^B)Cm)U0#t4gL?L(Un2}P?w-G*kY-*cq7>*x!gFgh!=1MtD%IW{!-GWyJrbmI1y;&q%coZ@IZ zgw6}jrf0uD>GZoehH+(F1ZP|xH^Clv(9LXGcr4+-fKI;4%jALQ3Gzz0Z1-V2)FIAj zV&h|75d+E7#+Bb?J4RHbhp?oFa3?*bTv*!Wjl*{L{bbFT2Xq>C_k)ngltm8E1p*i% z9~}lJ7}-X2-0pF6{TB*CP{XR$piOT0D_~2ZEoDQYm_OVS5VWbcco8t~7NC!`MQyS= z7qzAJ0mHZs9QV5#bvKQpgY8(JQ$_GBQNX=>7p)g(1!nC(dS6*|OGGo-Mc5*_ATb(j4Otj_A6 z%3+=ZmAvArx*RWC4x=5c0>k#An<=%J_cy@Vc(;L_`HD-%p-W<*;BZ+pGJqQ&A{NX4 z{+kx$NrJYMw=5%kMIC`fpmQ9y#;kk=m$)?{uQEJ5b53-YxTVfL3yq1RfP_lNH(;&j zI5qIpMf;1e&x^Pgo1U#a@84m1QXQ`IsJ2cERiAI+qBhl<_hNBbd3OL?JYSgyrm==w zRdtkSs~g&oaC5YmMU#iKpI4qS{}@>Kc@n#@sE#&ylDkQ0QIRpv7Puo1?qAjZDYzxZ zh}f32j)2<)|HxQl9A^||-uZvWZ~DV`Z_Lu+hGxM^^4)-8vXMueNXzYrMghZ@9>UwN=(Gg~qfy&N(VtqGWP3n%pR zdYmUYF1?@QOy0BrfM=^`>nQre=o6AfTCs0B~ zaFbEJP-2u1N-6*r5ZdA6L6~Nq=pPuRk1jH#*YXn}=arhcDv0w&A!K5qfIS=7fl^%9 zoQa}r=D-n}rG-&^ceXhbr3K$2yo`ttT<8>sRrwY}ymKtH80DQ~QC>YJj;6THi`@@e zpDg|2w(6!+4Q``AiOzUtp?J@1oL2?LXA`qS7%QDw z#h;zrHH_=|5`-jh(lAK-SggreBo9075lad{n@#}N@3Bbb5<)DH&Ln5$TyvqiEL1v| zxQ5TaYDkEDN$`&1)OkYV4UJTm!z*Tf!nnl_Don3rR-7+dUSfVSD>+8xRth}yy0Fq_ zsJ-G@?dFHKnkmn!XB807s&^Hnk{|D?A5kn}rXeMa$@tasDvI6sF`V9XE?^p4Z<*d| z5jXXzBC&-9@yLR1&ipCQaAX*+>EC`8*M3EYW4N?d#fH(O4@u}1l9;vC^6vU2BSErfkbYt2qPZIJgV(D0E2KLp5 ze;a#{ChNR9Ha?Z)J+G;$JRiaU(hCE@(^KKL%e!%Lhv}4`SDE^!16>Z7pBFs{ zqHwUtDboi1_46AzngJ3_qmcD{O})6}A_*!;*^IE4)y*vK_?mlpyXTs6}Lgnhc0o z<^aC^HFWlb;zJz@nL0*$fE$5{otn!~rraD7k&|E8U|=q@1J3bImfT!!P8y*c_A#Q_ zrV{0cN%y%5^H#y;LROZ!_8dN9eARMb^>xb(CboDzFyaH)McDU-WpD()8F&KDD$#>6 z9?A1D@DjY1Nfy{1W~Re<^nI>FX0eREV$Q%Y9}qORlv?TSH>6gw^m5geAe|576y*?C z7d);=WVRbi%_TS5HBKdBmLL6@ej~(=S8K_;?0o5UC*Qrx>E+2yE#Ny#G66|ExKuZq zc+G{LwciMl(z6;|b$&*;Xj#+CIc%v_#pM+Iv8WH;HHb?Muu(gOYYy($u7Po*x1DQ) zmXUYfF{V2)rUc3;IvAT`se$xzW!V|ASpMk^x)=Tsm1RO%=`|s}itOY?Cvv5_Vs^S1 zLc0L_!v1t1mkAShorVf&Tl%MR^FN+P%lhN__72Q(wRdJMufIhd=wDI(mriNHDp?jts{y86X(BS94d9^Q+IwIB|j*)#kCmV-nS=v)w{H zd#<-g&pqqBZWO2{h%7`Fgvp$Wut$Z&aOk+>SVRSV-KEU{pJ z8HSPolH+BskZ3@XohqFAp64aAGMFQ}8Jk_`V*(5MYhoPwjwM#^d;ibxoJQ5Mf-WN) zanWbx+ePwhETBu))8B3^c-VLB^tU~W0ruPii#VenO(#2WVhqHi#QLWai{EF@?)!_u zB^X0+DZ8YNK^%e=MVZB+{*=9p4fZHX-;!@hiqgmJ@mItyz{JEs9Ci_tu8KP?3`JHK z8;j^HLVG+CzDIj5icf~pF(TkY96 zja#7qkoQmjA#cV0E%L%v`q?m}!n~*aW1?5lBcmxt5+<1+8DWu`K zFU^7UOLJ*nlrB+)xiX{5bIEydV`)Mag}Le+R53fZeSXKn;*zSuxx-m`wuj)-wXZ?Z zAzAc_1epm}=X~4Ii}X+>zU}_)E{{bUYIJ)-Z(ZM>-R}InM#$pbE$?)g+3l%$140E> z=RDh~z)ZTM!0KFs5;OpT0zKRDzzuHjI@=?-T6w`D=FfnU3FZSp&!$-o&wPNh8UbE) ze*p*C16xeJyj?OcgLzHG{CMX5^UgOdUtoUxAaQ-cvcS6rsW$vDl=&%#EY`|8T#2k(aO)r(@e-YBAi}t}8LY(v?BljcMHL)nivi z4+rs{ZOEr*n{S)gm2X=BVX;40Ov2%H^=8ED!VEFG@~$=>Vpd|L8AnYv0@bh~2;jEE z>y&vZuQPyKg*fo>@|M%rQD=~4;lWb&Arkdh`x=BoA+BPc0K7-z^4k6GQ0$3l*3 z_Mh94-Jjci4oL2E#2k`c6>}sIq1oYcY2Qn++fJv&K-t9&KsjhGWu%P7=Q-Dj60|2xDA%7H1Ia>>Usg%LghjnBr!3^U!Yy6c`N2!h#J9Sqgnkp19xf?M-t{sl=rYQ6Fk7=rUNq zAxBw)!USKxuV3b?ef?41DjLIuuoM~P(ZrgI?KLS6&5h+@EW{Y)@vaLoC=YWX#t_ak z6dUdpE;gLx*snP3!)TAv2Zj<{-C(M*;o`9Evy!StW2$jPver|13}r~38P0P6m?uoE zAP%aUfi~# z;aX68h|41eDj&F%F2~Paa^skQyr!aCy7#IU7*W_#GUhTNy^Rfmi5NE~Ju_RfK(tsj zFunz|x{KRrM2I)uwc{l%W-c+GHy+^kG(vcZ4GkgHaj4i7Okh1>8F>jB<`Ti%w*?%q zERQ5Q*^wrhbB%zv#@oD=wT*}V)`%%~rU97khIva|brQL(PI{)a{d%S_s=THGQz0F} zLSxQ?lLlga(nRzEQD-}d(XeFo%q``a@=h7=X13)9It;TX3mkM40WLwZ9h{6#_GD9F zJz+E3WWa3Y$N{YxIBd#x)PScZ(;Stj@sMn%iN7h^p{c|aN;|;;E4Fk_$Mp4yDmI;B zL~1(Iy-$(ZPMe6q4q_aLI@{@~;Iw4*DXer&$IW*$+v%wiXBR3{Ek1}~W;>1ff}U&& ztS4+{n+%xk202_7tWDX@8}Q0hmD3MZJS5vy;&-#HN?YFMwEWv!qFa&2=+?L~?Hb3t zq*13d&L!Za3B={sQdz}Pws_={J6;-!84p}*2U(Jw()5_-$|pV#3lJ|b5hX;Dv13E+ zofLNAjP%-^n(a8eFr-4QrAR%|Fg^U(VSL)3T`*>&FajQlj#JMXEcb{L1JhZ!G5KS-F*!Q!@K}zmV(d3nNRtz2 z&5;l;Z-%1aTWcfrQTVt9?iGfQL+(Tyf==bIALkzpae_>RMq{IpIX0RawSNKA2&vJ` zDCEhE7InCYg&+5AhcWgIj>X3Y5jqfClhHBo$I@fSUK%SWqS-nxxzxQ~q=9=cF|~&% z`)jYua0o>LhSRslIMv+QA_I=w_24=^uH2gJ^*0 z?nW!jdj$~Wi#Pph6=0PER~Oq}!O#-2+Fn7g10!g>;)ISbShgQr!7vL^jsbJ#f$V_d z;Z>_xKeu9c+%>r=-Yh??(iN@Jm;sNTG-8d*a3OBZvg4n{L+V!6nn#%Bz?D4{2XP#v zs0^Xzq&e1Pv%F6?iw&a4Mck3ry%-<@wWulz3azMr4;&p;L1zqdC4k6%!_cxMQ&Vl} z=CoDVp@-IOY-6R#3b@h>Hfz1gIEoIWU33(k*56V^XWeOL6=~OTV?Ax$S#tJv7#U4F z@;T#9*moSOn|3ekDCtZiOc`}e^f}E<F7c*jmL!TnEacsJdHjbR1i5PoIp*J>33t1>1ij{GgIo8Oa=<+*OYYPjHnz zGlw5;NKrKmb)h|sa@m7w+oMX`0Ayq5xoscxSWs2h+}C1jn2aUD5IlA_O1obRc12`t zlqQ4SC8!KZY#uiMa!wxL5uYrUYbtez$@Jd-a+lPc|oU3 zKZDDb-IzVoZX*Kj69{$IuPPSppTsLbhKL=_46!)l){ABA#9{6W*r>tDLM-tuLgBU= zciYw^9WydwPavJ%bu!PApzETp+Uho*%<4V^f2G;fZAm-oxt$5LZDFb+Y>(UN7f>_c zG?M6ZA~FNn)JwDi{;<2gBztn?VrUw7=Q`-S!Fq-bJ1)?p#o9B<$S^08O)Rhw7CdxR z+^(h;UO;Luc&wY&ETJx~2=&wp-~liPYD~)b&FNwlA8YX~(24W~Ody^DAH8A1`vJ36 zdf*eJ-(u77p7<5UPyBO}Zs-L}>NR`|UyfKTQ$1*!|8bv*H+Icp>7VXF5Izr{HQ@qj z`4(n9@IT=mJdyK3zlpbf0kCs-!T(tY4tcf?-UD4;6+~ zdB}&|Dp`!bRAIP0jK#OwuxbqFM^yn`1vIzSQH!dK)JIf(q>aritRTNpc|EQ4xv!GiZMmy{*oQnfvmdsOWn?_L$#o7k&T zIQCi<_ty6kS}|FYa7hsL@&+bMf;#lNvP`JC$JN#Am~;t9 zTmmW&V@BB;vyp(or!Z-Xjc!4FDZr?2t|$xkh}EY&+c1?>+{UF<=y8}v5B|{WW-4EetWO7tf*ZLVf&pZzNS$NXW-sSb{I{2lnhdeB2MRQDvu8# z81qjcblipQW)Zgpk%Ce_TTX!K%37>=8{5Z4L(!F0f*iaM2a&AUdL|G1eGUp7AUy zN^dxfaEleEJ?`IvO+`i49=J#2tXyQ)Vrg0NnDvC&&R`^EfK<>5GsvKuijHf@hBmoi zQzf)W*b&&WE00Pll@%=n(Jci|+lt8z(sYqDJYX}(@g)@||-~~M?^m0=D7JS1Gtt1AMgVAd4c_XR#69=^Nfnq3OsddicG99UQ<*7M#G<%rP1U9` z`B~nET_T=YtnSulH-je-Gd_2hPpRInzjO501@WpdksNovo$^3A8_VIa8T6g&1x z@N-y+QZ-z9YeWWiBo^c*VU@wI9`MJ#wyKTw9pzp0F5*`4FJC9t9b{F7MmtYOMdzZO>E2}`T0vf5fjYqFMGQ~9;Rnkuc8*HmpS zxDz($c(P-Ik6%^KUQ;jJfSdGTa@QKQVq}zqp+&7}tSf8dtYFu=wT{T3Eo@UcTg%3t z5xkxBi}LoO9W!!m`(2UZHp&7CID<~?p^Q1@Yf_bQHn2;$=C1UiN8jpGLEJzpw|hd( z?oc1*a}#}X2`H*8dd4_9APy78jf{h61!1RI>;wP*xO)@$s;>ObQ%~of$CD)?iKhj` zCiZG^T*jUxo{;<)J2xD&i;x5v}xkiqfo ztLf-fOMj5Q1}mvNE`m8(8J(`YP-!7<7P!XL@s-hul_yt5r&gX`8NI*q z_+8OEe4z>^5#BpEH@YrjwOG8d32nU>7o0((H!)7 zWvJ}#Q+G$FL;CF9(L0uT@Scl&2b_bq?Hujs0}kqruHSobb#!d?%d4R&j@phc-uuD5 zkGGAG3pCJXwR->w&;?s?Me({a9(V4Yp*P?Z= zCH==*-k}NEEI2l71Zt^#c7o1DA66QRt-Me!5Me2){s?a1yp^V-5U zcz$#dpZhotEr6|yuPu%aE;+n}L;6oH1F4q0yVMTxhoF|fvpjlt`MKrM`Q`5|k1i~~ zwmdq#;=~HJke<1V{hDu!gxNZJmhF!>mHt4bkE`?tB9fO^zOvHx-r2T2bgShbERT+@ zIKCn}$yPrm;-1s@L}%`K`=03BJ?Dk6m+l4Re2tV(k-oPky0GTbn&^GLg+MzGy!}A* z&I9Kjh|Y5?dvx)Eiw{JXIC&i$dg#N4qN5KVdpLUe;o}cSCpgHN;`~PMaJn+1e&pyQ z(aVpVeFR?k$UBcj?>%zyk?7JRA3PF$$oauwz`Dcr(b4*2_0h}quhd7!>tCynPS(G> zK03Gl(s~X${c!y#WlpHf8}-ro`VV-SgG8g(*Po=|3BCPB{pos6H9cP+eOQ03KDu6i za6M&SUmu-Z|HgXGBYm5KFE_s27`@*3Mq_lU@l0cMma}phO5=x((Y3}`GE|f~k%>-b zPGzFgnX{SbZH@#5kuujZ(ZTHDY;-jHS{4$_p3FvPvTtXjce3ZQ(Rq%fq~@lVo1zm< z?=~S?o6a{ymzq9kiau<*))Zam&_bq~Qw%v7@a%@@Z4LwkJ{ym2j9%V&aw9aj@zloX z?TznljLvO*Z)0?U!#b#M)61KpPl+KV5*C@OOj!XX@!N5W z-GvL`sEdxdmmTKoNn8kQzY(Lk$_eg;*YUK=WV@i9LkD@rK^<_HgK(F)jO{79@yStl zOb&@x9UFkC@;&zU0DRq^M#lrM(BNzj54kMO8!w|iyrQ^94`PYE#*rU5mro^89)f*# zHHAWVJrx}`1@2VQnIc>8<}Imx*V(6tk;X^uqf@wo;o5Aa#M^Q0j_5jz-893N%IF-Q z{f^GFM-X{Ya-swy?p6FCYyo8EOD>dP$z3c#89Y`BVCC+3ulzzedtxq?M<1}90VY%& z9v8jL%4u|*O)0d;ItiNFnF@|Fv?uS6i!)D2oqM<9Tt#$2Cf{)uc5K%OgvQo|=ylez zxJ8wU-kI?31j0_vPlzrMC=d1!`ffa$kxjflF*-Ww0u0!0k4-v03H{}~SoOt8(ffqY zL|0`?93|i~dWArq=vCNt^v2}VlcO_}&+^`RX*(Auy)U)ts*H}KV(G6;j*d@$b#nAN zK|Imv$!8`362QJ0&_d1=Z?;82%+T6lt%)^{LUpx)1B3t3&#dSsT~tuGd8e z*%lzKe~u5Z6Gs-kI{g)SKd>%dV>b#W#>p9ae3nn$s?3E@=9&owGT)i@uEfWsY0(GM zu217cRD^;yq%cD>j?chMc};at(MdEikbK7V8PUO+$I!D*%rfoEgvJ}QII#M{ETQ{n z2GRXQ;#Hg@Y_YP6tY2S89)=rq{k!8@*1X z675eqIf($`QFr4b5WgE^)%%=a3b9STFgf~wSmx*|k<8I`Lbhm*ZDrAi zQ?AN>y*>pK;V4@D)K{ir1H3)eqC!V0b690wR+(3)Mz4p0?}CIE>Mquq^^2VgCSD`{ z5k?AbMQ_YFh<+~fHdwcYHYWo9@%R*nI7b&aefguxfLfIn~ z^Yxi_sIqOsh~6fk7WCr4-@JB)>#A~mK{S3+wDbW+l6YUX?T3lzdIA^!dz?-~i>zee zjX4FUJ;o-|=oG6RP?;F&MfvX!M@J*h(0K)ZtA(oQVCpcu?^NnsaILTmbO}~=P7F?q zN;F^ehXwNed^(Z%$FZeaS&)mKzr@a#?#{NJo`S`Tm$dHQv#7VNr?+QGKC@tJTW9Oe zj`ppKwQ^k0+SS?9)zP-tc7+Z;3SWL;qnt04=ie<$c%M%DqGZCSGMpOl_3=K%y-)VV z*Q}qEOk{jjCgUe1e4;OTWaJA2A64E@%23=-Odj@=6MkkQ(eIa0b0XRTg*=osdae@4GF6jvcER_xTak?}T{mz9d z=h`)q^R>EZ@~l@xQ7)8fh)Xs3bSO3W*5)|9oGb4>tV_nv3l}{k#mY()xr$79*>&aO zw_QobSLm7gXxAoRHX_YHZ%AAF316h_{L}K#LX)4U+|6+_K*}1<`qCVjko7e*vn0c9 zpD#^T`kDsirhN(7%A1%>^ba%w=|(F(!LqYH&9#C{WBjX{D#)9Vbk8s%-W~9jq(dXz zECCx_QI6)^|6S1UCnWp~a_53J$!~%ozLr!)pRYaS7i4@b{RuOgNS6E3rhu+*3STn5 zjLD(31h`X_+{d-d7j5u~1N_q8gsZqreTifym&`#+g^}ymkKNf%W-zI{D5syaPw7G* zH2pq#S-&bBepGPST{7nrX`_w*|1{&6DW;*6pl$Cf(|#JTNTeR}sdYd*V|1TR4uBTS zZpKdr1oJ2{pnJoic{#iem0NuyYnVU{y&qRY z{|~F7c3=R+0LPPVcfYTw_LJP$em@0-qtlCWu(`f`YAKUxb7|aTD) zX>y}=5q8*TZBGZ#RHvT1clQgrmF_nZiNikWKCRS0LH^2@%q$(O^}DOD>;6_`yekCLa!?TckhmRWNDxc~;| z{@Q>k87EI|F={$De3;he)?5~zz=QyY9f*L z_fvn-AwM^pDV#gb-+!6jzZ8!OhHWFc-~C{JzY;G|jTe=bB;6180m@21te*D85b?ySaVyJbaMb4!*-v}h2i@NZjM@knbBUqpPL8l=HXQg zs!9UkyhNoy_{ls33kiZj8*^(+rE9!Rm9D3^yS;PAC<-nl@&qA z$3+*%>9JNOPQaJOxjkadZfwp^N!Iu~H8=HnGOJGZQEd(ER4*LztGQ@Y(zG1yH|l!X zKcGv-H&|}Q3NyxWU{XznF~d^CA?D}&rmUY2i(!zrlz|qy-_PIZYwCGtldmbI&X0xLfDk#?*qJV&;C0t|PD1B1%ARSlj7}RpURLP9zm`-x7S)KuU zRg_2`@HKXo9t8C#l4eJgE*($9m=P#>)2ULbrwb$SaSI-#A(xBB;Hh)It_YxTsS6jw zOJ30=sZ)tFg`CPF^GDwrC@6U1HtAC|)RS@a)-N%*P#@r}=mgCmB&tFEAgWlRj* zpYcmGhE0hxo{+65;hv|XLa)STvz8?N?@%%z9om$CL`n2IUDQAB?FHbW6uOk~5)2pf z();#;aVw}0TZL@MBOY~3q{%Q>uvf&15kobkI40vKVilp2@s9Y>G`qqNbj>GYq5%`& zLx8^zWwabBFW$fZU@$3*hG0g1^~eGJlYx*>j=y4P~y#pqWvs!ZKxTz4@hFw)<(zOWpg z5EIa^yy}RfHui%61c7|v+?r(HVYIMcGA-;1dVi@qV`?S)?J9kx`!UJ~GjsJH3{`-_D?N6<}W}+1x1Yv6K5}6Q_8JS1i$f!A#+S`yk zoLXBrGmSPzGt4jD_5%Z{zZyvW_1OWu8vot8Rq3l_M10@Z=KKm6xO*Pn+hp`7^FT5c zode$s8i|MP1muZck3BAv^4U9v_{r0o5;%_bx3LZPtr;ib?BCV|na+#ZEcsxAp5eJ%?^ zN=Qh`I+ZpmBxOQ5u#x;TbbOUG@b}5V0YOUOzGx%?9$`~RAuAU=WkCp_?qP
>__ zhojbg*OxSkM;P0+OxPdnB?+0$<&8OzwruHs(5YNc#wU;X@<#D|Y#OVl3gQFTD9p6o zjTMrnkhIX8zY|kanumFIM3L3L#AS^L(%%#={7a}~oco&sMMOyT7U{mM#PR=5TSmAhJSnTiK0kqmsbQ-ivuK`8+X z6$hi)f1nDUzsU1)o}oF9 zrAfCvVZJ%!T@9@lT}f9~A}C7TRk4)OXQte}07hzN%4spo%;k?PZqsrU1|io(%Kf+f zFd86sm>keSuLYBKJoU}O4XB6U8i*!?X}r59=jXctq*`h6vU@9(7rx-q#P9MO*n%Z^ zS}&6$J+TDvUEwOb)m%pzkR1g$$&B>XG4ay}g z59vgFRw#L6nRf_Yq=^8MGee%**v|ov$(lnppl&G?x&lm+uLQzhLBVNadty1>74;uR zB<;z|w?5quq<+o&Ggm^FGXN(&;Kwtcyr~P*i;_eKeP8N6AcPwMY^dZeb`Ppz<``^S zlyrZHERpMLo`%4Kw+5uhfh|S-eiEkR8MZjNrx}F9w}uU~$Arqgeq7dJw_ z>$Q@919l5g?xzcnko!q${uI|)Xrnb$^rlEkQ0X&6e-g43mTC~`GdVg%Sm~}J>V$*0 zf<|=rC6_>Q7tT%NQtLKlw8mBC1O@k`9G0#+c$8+5CA}@M5CG7U8!>)2qo3KucWyu^ zMzRn1qNV_YNv@QBH;n=Y{7y}DdVM+%hx&ehk02F{)bVhwVUT$==O4slGb=gP0CLuN z3|tK?01f~oeGu^A9g|iu#VGQRZx0&(21^-S>=C!5(;}ukSc>*hDf9o+Aap6a4@p#2 zqV=SHE%jG|dldxdo&p5CvxNJ;H~kFZ(#^kDhG+HpS*FSGTXZHZ5F^)w6dLye5Tnm8 zLIuMvMXnt+5aXvo_0jK@KD&g(z>C8Z;lA&Tkh3Id+`lhvj@WdAXq4$dn0l-(EgV5| zacY|7-TXV_Bl0Kf?SAHKn(ILa0V+;r)XaYPfm;ienasb9nzXQqsq+5mmE$G(+ zer~_NO9O=Oqf#3K{-yneIHr8+uLqe~k$Y_)-ZwlzrVxBAze0k!{|Lie=>B{kuqbg~ zDWsD{=rDNC>fH9rzOf%@)VLQQ`uXnjVA)t#hcH6FBBgns4jJ<-$x*O5-u3R^?oYU9 zO?rIcGP6|;J&OGZp}DP3_6^u1eYlgr_srQ@W8SS~Nx^0Cwc>;3w}#jeZ@)6$KWR4BO=Q3WI?Gz>=;E&)irHPGh3pO#&Ci z_L3E`i*C$QW|%*8lLuh*)zJ5vn@>Rs9NyQi3UCax%t@$W{8QkFt2{=%NNj6xw zPo9O5CFFp1y}1bn1#ww1>?!z*lkW4W-fA}+nNe+0nWc(xcwe(&jV!J?cx6;Pn{*Wn zH!ay^(r@gUn;X@lpi8D6@C$WQVahe6ok*U^CC#HV?qHRSx*KYjE}Ym9TtN&>DT6P1 zl-;!>A)g9ssV3j^UeoV~n|K7ONAQq$F}14CSeRTH@{A=?5364M zTk4@R|aEV zZqF68Cx_uZy5`JRiVY(Nhm+O7z1$2k9G!(`^`PLZ3`&PC(0i?}IUBEh z3-$sl3d-%%Pg1i?`5^%J@qGdJ94_^0K>S&7A;xiV(>Mv;m1`{*C(wmF}u+#qAJvw8N$^{Kdr$h;L{D7azopy_Z&K9?5!%C zInI}){>J-8^dGW|n4uDuvYX_-q5(7o>^j|`qCho;YZ7$eHzm1-j|R3pVkk`ebl43x z#B%63={lt>A5@LP+oT(hUl(;vESaZSn7&)70lLiq5dT)vt(4K{veJTuewXn`(1q#3 zJhD)sS$m%ji=8A4vs$43bn?yMdhb_V?J$m@iKksPVxN)-_r);YwDcf2CC%Pt%|0&N zW9gKJ;YKu^8QyStX!sr)X4UhihNr6GGk|3SW5q|8RKQ4y+azlut_H(49*A2aMa|uj z3t*+{aR_Ny67sI=TFEu(zBUZRDg$fls}8CtsKN|mAHM~BKcZyJFRbKpD=D0HyVcc~ zOt-;=oy44G3@#=3giy=qdf8>FJT+S5BTyCa-HDP4$|sVCj6Xc$ zx141up!!W_ZM~nd0cbsaSx{yj#WYoLi4<#!Dc7oXxITM_6;8U}db{0MbEvtHLYV{+ zH>^jn_Rg|tHrdxVkoV|+Hx9B|%o_I%aZZWERJIb^zv4pf%akHq$$k{M#DdzCL{|Tr zvK#DbKbyjB6PL|>L)oFkU^zWz_cF3eRZTqTu+39zQ)^vmYK>lM;=g`J{@Y^7CaR5F z**x<3VD;H7*4fBs`SuD59>1kQj~^WLTn(BZ^>lI_SaD;;@kk2Bg_yC=-vrC2+K3tJ z=qbpDiG7qdv#qT)tY8dV8UgHiHD|=C#pK-%P0@ zA=uyR<8@y->L4ch+Y*_m5GC^eEGT>+fse7s{l)<#(Nx7P6cM*zoTO3)HEt4_D$)<} zBA~!MN$EabPP=~(naPVLZjPH>i@2lSnl6%4E7+${a9Uk6`)8~?qB173eyZ40SSUgK zN{U8sD>)Mt1EiiuFqCkKQ<9rxS}H6RM3}5vYKbHPJ;dH2V7t?-Ip%VkWz?+BNtbm3L4MU256Wfy*mZSkcThY6}9kkFirqk25b zEb}tJvAl#*PW76ML^hYn_2>MLxu-Q^I+cdeRLF6&j4+XjgME=Ro?%HL(a_Zy!rRn( zM1_OHlL9o(RpOJpn>EOcUrX7i7&0C*T2u<@(Sdy7#X?)9H0Le(=3(V+EiXtzk-{a# zBcFzK9Mqy^;2l+lUpQvw4PuzD3b&d&R1GtQd}*V}61m-{P`TEr6O3ziqb-bJEWtq0 z^*}#|{jJ9(T27wriu>`v$+scn*4!1-u~`?AMx8>egKzV|a2#TA5mcW8HtA$f>AH-pLhTWzf7von6ks;HPtQ2Sb z8f5uO-kDbJ*Bqv1c}|j`L>b1BulbW&>N63e3I~#VmPY0zYc1lFrS!GD-9XWes+3aT-vE9JRB+w1Chik#-Lh`-Z+&qO;rA%!Eb)XKSs4R^z1U> zUHC%iq-Nr%na~yVM9L1;tS~JB<|4iUdYD0F3!P=&A7LDb>eQZZ*kf+tIK}SI_GOG& z{ZgUWm(s>oTu3v=@9m>LbL#SYhZip>FU($rGt6`a%`FV1rmAZkcp{u`g2% zG|}X8exah-meFcSYGeubuc%`(OU;nU|6o=aPYzhVUzDAx4=jLc<+-0sjQyBDgR$a>FMUjwkBv zQaLHImBiW!NEmG>uC=a5>`>8TCLPkCyFIAD4=L*X2E5Z)`!i%eN<{?6l!EkAl3(%< zNP}hF)mCH8&vwOVUG%hq>hcb(D^@9bCE|zjwPvhp_5X%O&Eau}^ua1W%fi+wjTgYf z>H8F31&PPeHjoHRyml}z&cGIzJt0#~W;vV%sLbgHiR5DzFC0tfXImXwSYJ)f16%>0 zhZkz`mezI^E~G6UjiZy*kSpQT*#>prRseLB`~k?N$qk^3*1{HmE!0~9EKA(uRHuny zB2h@`!V@^tN1K>64!%1LaOuqf|8SX*uk=M;Wlp;hTw!_-b7i)w16XX_!rI&e{Wpjd8u~VcO5L{z9V_CVQE@L0Ep`YC zHU|OAs{@EI=i$1R-s@?8jF5d6lFcQ$NXlg4rD3`X^;pqmRD9$*J?!;QY|~e%(2||8ASJsC}AwB5M_^Rm|;%Wf)W>TP9(1)kaK>$m@{=-EL^{- zbhxoF?e@yqL*4+^oWAdh+K5!ql|;1tTY0eJ)N` z@~qVTSwRqt6uwO)z6cd*ozvR-#RDKSNbUY(K~7C2-OnD#R4FIvE?Miv?iZoOVIuY8 zS;g+Yi(HUs#7>lf9Es>iPP#T$&_7YWzLq8rh= z**}47QJREl!ms63zU+WszQI?o=hx<>O|!q;O$;;CCTsiu5g(ZNZ7)~(_T$Q<4W7gGV zglz!tM9{f1udjOlq6i(LUzv20sYdx#{!!K;ioS||Ghhk_x+J_3RRNs=_v8dBi}fnM zrpk}~x?dAuvR5!!gVAab+AEmEDPZ!nVeA@|mH>^tBcbteDxiO|R!bb?uuj;Z5Ogor zy6zRKCHxay=;dst6>~Y~A2kZMA?eQbFu}S36?Kux?NFI@K~>fzDf5+p*jcFSm;b-O z%^U_)qtO0`A||`S9<()Sq{qgM&<%s%P0uk&pVKAbUkS!`!oO%YQb;jhLvEay-S2nv zDqQ{*X{9fs4ZR|+$C16i1_wsxUi(@eP4Hbho0&s4 z6A6DJKQ%uYrY6o%1R+!OXup4!*Kog)PXj;6w47jC;sv>hr))uP$B*dJ+P-_wXb!Ed zyIOj8hFy`P`nHxIbXw+)oevXJEYjk-oEW>en3bR>as$neb-!;G;Bq%m*l+3IHVaW{ znHS~*$SOh|_ED6qw<5o{FC(@w(S4ON=E@rD;ylFLKy3HDNd(F*JGXpEy*yy3FZo{@ zNV_v;rjB*LW1Sptohlcv8tXzo%Pnj9V3ztdp4ZIQ8Ee54luo;EhR&cx!#pWdZe=ja zX9T0QN_rVXI^wJFR=|kICs{F=NUWMROQLGrtqUb)+7-~~nn)7VQh{qi%3%c|j;76x z$FZ=`iXDk#_#q;t5t-p)k^O_I_?a~XHd&d_P~rX%HYnVae@U^ug{;+B5N#aq_uUYS zi1?BlLkmx(axNCTpWN5aKug_s3#EZ5E#QnuBYl)7ca|fvButzV?u6i_J6j=SHEBS2XN63L8~daZeHs3twtP?V zav1%Z8}ljOdA36QM$Be0vm%G9v{1wtoS~j8eBzz`#A^g!9HBdjZ}>^6J%I?&eui!i z(W31Z_7g&;)X-E2loMRX0Rz)yuVS^C`)VpqM*N13wbwgb2jSRc%dk^G)GXl2?J{oV zuTj;dGR}i@g*?~A3l2jst*}OUa9kVn!^(*Q%4DNnk{x=*7S(2gwB9w zaY!^-$9_gB4U=dGN6{6l3fT=8oSA&foPg*P^3G8p{}!AaE%-?m4Ty5*_nly$?i14^+@+JxnvocsnQC9tbD;(}pWWI58afT*!@RtM(XOucNF zCOUX^;F@=n;d(z+i&|C*?aRN<;S)9n1$= zxKEvAWsy}L=xdcwuUghc`37ISh482+wQg93`ZLWvox+F$L?sDLZmjxqD_WZdof3D( z9sWN<_#VQ3NTykXk_(#H_DA=Dym%eloCvVc9Ivh(QC3@oeAS_r^ZYuHfkZ6;KQ zFw`FMY`&j{$DOVeS?~L)^`n}xceU8ERaxOYl}(@>m|r&AD%s5wFj?KhX3bwU_~{pO+O*Sp0EI$IZ9 zt#Uptr08r3)39f;G}+`ZB;skH{7QAYN&XhL=TepxG);po0BK5w0cmE^Ek2O{Omno^6q;D;8{))AKt6|%2=)UvazVyyk})KuAIecozc zXmLG@P^=MC8lTu+`6fSkou6sW3Nabwp)HQgKnb21<;&5z)tW;0WADH` z^a>m>sGLMYUCv6$x2+nb?$-lbk?>_xgtl+gXs!^lKLb}O-WVm^`#1o}ajzf|iZ^18 zFjGP4cYj-OnMc*u+E1t^-30|%cW^6RsC%pei|4{dSe=;-JxW1a%5`kwimg5krM10D z?1SZ?lKonE7_+G<%jzQ#;-nZBAWLWkbb+cCr~7EAvd(dFSi7#heA&805&XBtdXOS$q_ z(i32c-(xHm7`s_`O!q^ClhjM1^50@fLi**K`!lhES(kLI6c}YOS%rrOcR*_S4|7)j z7B05t&*UlP9zqP-&3z$;f#>&zVh@GO$an3fq}~#LgiWAje7hi*xt^@n>?0r)hF6_D@dy24$}wfnBFNTFGG*-eI#{?7Fmx4xNHKVZ$8v3+Bg$uYETx z@*uv<+Ow5m0<2`+Q5f~`Hr9lFlWiB7$|63qro%`U26x~V@Cl7wZt1_+kA4LMEOXre zV9=uA;Ga<}ibT3JWqwaE@z>w(OH%`hYst77GBB(vx>l&;o;RG-#eVFoF9SKwO0 zaOpzA2cKk*gff_;lzIEdC=$&Vua6l>U?YRSsor<30)y%Q4R}>_GQrfOXcnFZ*;^^Wtx6HwjOv8oF z59QU8N;em{B@RyC%jGOqln%40K_neY?BF=YVk6Jhu2K`NA---%w4NL$YV)FXih`5J z5HhXBTuInR^YXP4`C2Rts@$yD1G^oQ0Zw*Q5B&|YcBFtEA#G*N$71;A0UH=hzzP@3 z-KVe;g3T62mU7F&gH6W3l5WwkaTXn-Vh#yo>MG@Blv;$wg9kt&5N}pV5WEvONX?G+ zp}P}IHOOvZd_?1zIPR<8$UbZxog`hMD%;0!H~R@X0LzpIKVeXh_)%{W;N_q`=#j@U zom|5ZgRiEDif7tic0T{%v11fM_EyMOLf$jAAs2tkO%Ib2I8IO9;(j zhqqLziDzlNN`9U3t{3B#Y6&!hg=jh9HhBl*qa$pZ4;{hXCJ?Q4Phqk%f}aV zaKRz*d_T234*s>%sck@jil=b=!3ZVd&<%nSz|A3qSdMq}d?VdaCFE^t50ANW&7k|V zxg5u8PjjeS5qRYv=boE<6kKBxhdgwRc<9o%;GsJRX$eKm#~0M~3B#OL9tT}sS-=^f zE&%{cip{1&mAIu+&Bi$xb0JJSpt{kh#V5u*7iWhKh%{pJ7 z`dhy!t5t_a)}$COb~HwYgVCDtO9f`!BPNuM7H3a+!>;LYR90i~Css=y@D|#Coq%gD|yM5m_+%dh)e0WSkr5nwO0d{tdGH}!6G@hg zGzy7Zjl?`ZIiHOS>HI6;76Ysyq~dYeEN1)@%ET`nE()C|Wmt>u7mp;pFUh(e`(Z== zmN2hBv|~&_A6A?E{04rV=aZJIpHNtB{*G{%!#;r%+?8ota4)e?MhTW6|2;o~K%bo=sN@-G3^i>!7qun24KrwZ5jQX$Z z*Y$%3+443TNXM|#UP8B!DX7cO5Dq5{Iyzu@`BA^DUi)=s9F%#v4DA{2 z(A1dqGuE^7Ws^_U`^}sDgN=SOOBU<2>)?jW8SC`A%J8ntg&AxuvF!<)X>*-_aI@dc zOIiCxBMmv!eMnV4*q|0vCHb4^9Thydnb0*of;xH>Ow2Z_RCefYNhi>Hu&XinghNn+c1>c z0AMofHfd|ZV76awtpHrQG9%l#AudjSXaVprs>bk`iL)dXtZUe${Vg+^WL%}_-g>`z zgMTodB&KY$O&O+@<;g->MnRshW2z4O%}wgZ<_+sv)S(N&kpc}WtoA6fj)zouU_>s@ zQq~vRnozIN`+1uK{N_CxU$^+B^og-HQ76Un*53>SEJl*Fh7>D#6Y43_= zY4EjMn1EI5d@ZX0>R9cgewA>V+f{`#YjuzaOE9&E*7=DI+TFT}gTOcY75oDF6iIJae+6zD zk<yql8qh;`8wBFy+L{89;)udT{# z(?MT-*v<^&`Nl(Jqt&h0LfPV+1`tx!>XhZuMzwo72j;HWc$8bJU7?z+#V++0FP0+t z*{iOd>go`#sVs0(pEyIf5l~U4f!PEasKJe}r|K+(MJ`1Q4$o%fDA4#ruUE*C#!2ie zHUY$;Jd7&xc=D28(ZB;>^C)*L^Hcc%1 z@Ya`jH_MYPG{&pXWj3vEs<+-Zg@W>^}Ila zDhG`7ZGLE21#Bia$!9m8$6GX~MeFRI$drxPj64w}sSa9SA@HXjRnQ7AaxCbIdOyns zp2AT~NPOrGtqOyH82z#~45URGHjX}n1l^wB6bcDlw3($yZ;Q>#Cc~jNg~)P^z)sj8 zzfx`hR>vo(U!dF+J7vfA#Xx28Gw6N3>M7c!u|R&6l~p_&ukk8p!e)(Oh&)G<5B5SI`yBRQ$@5BhR$mK zYN%ZY&LPiOb6w3wkBKi}{G)%E7@vpaWkC~!)}n&6E?duvwM`b{Eq5?3Oqx*P!8k5V z?u_sp$*giTpN~w-KOsurp7iFQu&I*+^n)TG-B-ulsaYuo!_(3XP`ZN-7)oIs zHL)(p218}WF>wciq7$dWA$n-v`O24DBl*TS$|p`sH>C3`MfT~mxqf@tAIsTXivLh z!YrEZiU9&RC=lBl0iOXl*~6eJrISb?xDyEOT!B7inB6K8+(uw^G%;Vssl_|gvAlNK#yZn zmbcf1q>U=J++zyFfVNzaooy|6&lCiT;Mc}p@ zP-T{oMIy7F3xAecqJ*Ci%1KpI`QcYwt_VBq8?%P;FcP2Uj1X64K2w?oCfadmY+7z> z!!j}q-5E#>geC072>gsP=H#G^JtHV5K)}F=N7bN*J5*P(0eF~Yp&r|H@V${uXshxW z<0V3_5W<{p#GbUR+{WzKhRp$*6GN2qTo_~M5$moaD>gd5sV8PjuNtI8&SqlSA;GsA z*7%AyrP7Ua;|aX4a2*6=Z3_BuOpLY(izAwV7oo7)rMZZm=I}0zg)bS~5b*~FKj?!X z&?#(#TwY;pyBWz_t92kNnOuPLo5f z5abo}xiS-rg|12z&FQYj{M?fv`i8NG{Ims^6l#q%aK{kjo#!;dy;>pzV2F1OL%+F6 z4m3@qx^#>+ehO1XaA-)NnApRVGT|azUXB_+DKCzLt(yKD@ z%l&%DM-;MtI@{1#Y9ID|0-=$p7!pJ}fpUVM%{QDjfxI)m#(=eiFqb2NVPtxy}J8@fOop zcJD2-lSGE?qwr&!)c{?j&1gS-npam+E`K;B7 zN(WLBqsS9K!IyWfh$_zdq*Bf-1*oX04vgN$yz;R)V)xvy{`iIEd( zQv-K?2>0*AJQu^G_YjYytr;heg?(Pdx4a-s3lEtfgzYUymew4^0V6hE5p=QvRT2lj zQJ1M}gF+?N+Tw!^Oqs#&q&FHvp0zqMi@kU%kR4W_F?h`JzUWE(PUvu`D}E#PtH%W% zv%+}~zdg%@RMyAOOy4xNob{g$Reeeqycw1X_XdmlASjRIHPMhX52+ip5>y@_1O+}1 zHZlvD)*?>SLc)VjSe}H$3?j>X9bQg;ev=8uS0}Qt^l;T;8Owbj)okHD7d`{R%s-F_ z05ai0wgSI&jEuRvInp)fxA*&A)l1kECNQCNlai?(1vJGQZRb-O5){$B`s0D>&?g{C zwpm_?M4}7bYd>y*I%~*KNo9zHN2H-f>82+*Xl33Loi6&95Jm+?@Q3UC7#orx*lsmEcs6uswlT!|>62;JHUG^`-Y!tbF z6-insL$jf@X2;TTY_f&DCf&c`@iJ>w^J(oS-5>ur$fnFn{h&nZqKOYB^%8|~hx{o8 zZ*ARj9*3+@0eu~eLLQoD&QQUL$Mj-IAw9&m^u-K}qG2ic7$GVAvh2^cBOpy|gZMmK z@wM;sA^9tEzR3n-6wWi7Og*#__)q8jlR5T50@56RIAn6j0g&z)liTsk9ELjz81AcI z9FFyj_jiGUko+58jAOum*9p$b2yp&g7pQ>r5Z2RKY_`#`K3`+no%&*ar~Er{8>hdh zI5Yb7F_goeF;GRD&)C!Y>C4(-RvH2fmBIRtcc0GzUx~)49E!^MMFMe0RPMeJR&_bVCdi@2JBniSFE@0S8e)Zh@YW<&@`Wc zV6M0sqH^L1kx}Zd)`}!N66%09aVmH$;oc|=>2nr^uXNCpMo&+7Zxu>e>&(BDqmqz0 z9{DQ2o=&2vN-ByQJFUUbm*Q07&Jff;29`@CQvAz{OWZf9Z89IhY$ECrXRNf0IfM~U zlIx9%45l~k=d5zyMpRB8uwlHp&kkRxvVPfX70C@!ZluI}_Qp&nAjmXL4uKY`R{QDo zIwk7?G^vE`w9>|8jEj{zMFyl!R7;d_XbA5oP+rE_!JQBd&V~_0qq8a=(cxh^Z(=T) zCz^2OVIZ2%t*O(2By3<4P}Auuu3spLFQjfOTy|dZ=q3P0)UadpmTE6U(h@pGR}Eu0e_GphUJJ zPnVOJphg9TucMR8?QnB)*Mv^~!H7;mg#Rw?2TekOHV-L4ae<%(+-MBknvO~?WTNR0=))h!}RH+q8 z@{%}1kv@}mt5OT^{R=cTD7B<({hgw|!M0M@VpB^NsVNG88#bW}$i+(*CiEu{3+@F0e z6WR3}`WcR7$Wtzl-cdi@Y4wtO3UN;lhwg`ZH_9}kznF>EZf7$vqhGy2{LYNuD+nLt4*_-1L;@$m17S26!qyh$$+ADt8%c$~X3YBTixEqygCKcdeW8In6gWcaz^ zO=+LX{q{gddzc+JDCO4K(D=rMt_lCyoM)Bz$2Fv5{Gr$$V@T9`wP09VpAo(&m$ujn zo>~K8*>^#R^9*<^jkKiSnnl`vY_pH$2vzmnY8JuDawA$Fu7$r899c&}Xq37)jeRIv zC#iY&fHgZBd&WU+n^=b(LlsY;g{lFAwPCcM!1}}LQ?p0-!~El5D$v@!t%ie|U=zq_ z$pzHjZIw_6!@F^?2zl0iZb|({>sG5n>bHGhte_zM(mySbv9q^rM_c!3hmeeV^2q*| z-JihOF*LQoZowv>W{GwI=M~la1sfG=t2I}9L`pH~gcU+eciD%#7VwcC7*cTVm%3}n zLB!@=RI~vQuS?hmT<-Qyfu$PKYsgNcA?I>eOtqI?GWr+9EC}FM)k%8(PX>45l z^#q_y^6erB$KY7Pb{-h#H<<8J412lH;2UM`kNE`o0{3fVRJs>W* zS}VNxMQST`877H1;v#paEisn5KLFaqpsTG7`j&0K0DePncyA5*aT#H`@}js0fC0|> z!F^iT5*CWja(QvjsY@2U9zxh0HV-}016y7uC>+ zzWM8`nAdseMopHNfsVi9*yIKMVzbJIAwXI@wpas>)`;i_+%23zOtT*l4oUQ7cLxE zc;`6m6sKe0a3-#-Fn*oCDXJBwmU0T5Rl`|bA*MX-{)}m(x33?_P#fxj*wGBRcKC`h z+Z1L{GhK229-xB_Ul(vl5QRc54Js6Bas#@S&}y!-pSTN-~xK&B+;1k3=3nbq|TV#ki&u_bwU+W=Ib z+hBxw4~lt_5Um8Q|18#+HE*U14O|L3sQX3Jv^gR#-t&EPI(J)J=-}{hA3U(3-Q)Xm zRcN|8*00EY$F%!mK8uCcdmG#GlJ;4d!8(6tc%7HxI!}zOlNEn~U7K69+3==walbRX zlmBvfg?|-S`17|^VNmGb&nxslr|)4A9a^w1?!9(J`VhZ+6%s5fG{hgH|vLyjw;EArblY zCl1}76ZW+!ct9tOYXJ+1Ywr;I!uPigmGnrg2CH08b;?gIx5Bg3Z(65V2hur3d|q&l zs$zpNDJ(_4`T-jv5}8wOu)ZqxYZRQbs^4&b$nM$BEkD3>{k%{7wh1rV)4;2d zz^tJ>P?#fz?HnSO>)GsA2kelL@1+jv~doqk5xR zpbo!46(P!^Pjiy2lwigD-5rc~eNaS5G38CxxX_*S+9$yvohXEqun*KtsUGnR@6uMA zz!Li)Wi{M_&r#^ZS}gn)6JdJ`woa}8J!XKickc@X^{xAQm@ex8)m5jU{TMe;k|gUA8z*Xr+g_3I&Hk^1E15n1M1 z!JFFe?_=s8JUppEjPC@4QiU+BDmgpc9x=kAY zl=e4ccS0t>v_uDQ!F5Fmd<22`B(}bn$nVY9AB&rY@*rwPF1*lk^-PT@z*$)V+w%{E z0aNv{k;yRL8%pLE@>M2g=|frJlMZnCp)4beKq2r&S*m(-ijJLN7CbDLtclf9 zZpfoveTRwZ4?K~Q;el=PMgmSD)T4}Mr8}FwshEfWEM2D%zetA!vi}+jp(AX%+xCjbb(HETa_B3u9QyNE4t*t-Lm>@<{=yA%2wTKZ^eg1wjw0hfYdaEA?0%WU zN)WPqor?L!YQfaLMLs=@r`K}!pX5%SX$ST;3eyhy@+c2(m1%3VL~G%0K@~RqFcmhJ zKXp&EGKx~}x7k7;2kn64C2oh%g^6aiBy^cY9g00nz)svu){~i=gl^_0p(_!M%mwAY zL3jQqiQLOJsavIll)EW`Rc)2Bsg#nS!sl!Z3_;oQ494%=E*`)=IW9wog=1z0u`Lym z^BsoqrtxTr(nE&liC+PC0G?+{!}wL0gZzVkc78Rj%Ahe%%zm1CB0zAS;2Ea?AYbYo zWcJfo1P%b42Mynb`RE_#gMjg_;>yR&8Q1(H?ke8ZwyUfAxm)(defgmK4=DX{(1$)j zM3^*Tp@+lLZ)5NV$T&*m2suljNu@W&>pv{Ikgu4UU=%WDr7g|_CZtB;l61*zHcWjaXq|zIJ}tp zL>`SBBFu(hMeERr*vSf;gl{7Spmbs+ITyP4SjHPios(r z6)#(a%?!L^PpKjX*W6^E#mLTu?W1g2y>Y+`h2t1|gFLI?dO8?*AMbvT+m4^zP&*2~ z@t-f7JTG#8Z!49>?#m|6l@>Nz8g3)DG~asQzHjo}>JBHEDm#uRy2FYv({_!w?fg$Y zp&2fC8D}9Au$Xh0*8(g)K4z_jFQEzawiJ>H0YihBYMTb)!v}$}m7%PKLXf@*Q_p~H0BQf(aFq3(I7@P~3N!pN-Z2BRWeT;CHBzVGde;C5aNHAmr0Z)q}SP2~A$kcEj zmXBpK8lPc9o+sXEL&s9mb#Sb4Y9y%&(}P0Cil4wp&(=OaYzU9}YvN2V=bXXTv2H_JlK(=qQ1Z`!tQ+$Rg40m95|@= zWLg9+@`$vUBGzVXnjaCnNZU7|;)#C*Fd7qy=be*lDH)i^hJX6J%M8;N&0F&oGw=7) zKk@J@gFyR{W}T&!L6u{{Rh{LqfD=;qz3OKW-}Zga9`d3O&7NBT3~gaC><$Qe2tY*E z_@q9;rN>a8e57)NmB@m#SXHPr-?_>0ti_W7?oAXN@k87v9lOLm6jYG=G8|f^8A-Ba zBtY9Y)Ne%t!EbD@JrdWuM(I+={NX=Ima8#$pQd-Fdl(DxkhWbA{m!0e=A{i=6Ip4OlIFl~7jz z_YxrBn+dX;b-eYB*F?5o+ZplO%pN>?vW_&2PDZ+2>LJpS`20r53mv2uRYZqSm$O-~6Nam!u;G(3-o%(KQk!!Y`&G{VrWcQPB^Xfpd^6L3-Q*SjcEU(Wm zGT&o@uRBmip7-YU+<1iS+RHY|rPOG%xsz(*wF16{rKu`*og%?>IP!{AAVE6-ixdPq zWHI28mbG(}9a;!i)vzKu~@{Jg>OM`}?UW?jqBbZ_VEESv621(M!S z@t_rggka%V>&$E(1F=d$ro1*5_$gQ!5IfIaZ8HU(!yhLJV4+Uzzxv+rnhBs6MhslJ za>bD1`&yPA49~xrgsN#7pc5P{#Y9AlTpI}KJ=EO0Rqm6G^ zF#ksnG*)tBy#q0G!$9k#b935G(rp)Lhrq~S^WV$R>P`H?m!F80)hp(V8tZ0jJ9rzhe$y%f*siFi&g#dA6=Jv65|xfbU$!*ZyP+?}Dw5WaZ` z4`jjT2e?J^i&DgK7)R7c@8xqlXaM;sYo^Hk=h#-hwRE|=jF>B0H>?Ui0YesF04Qp> zDVN1R^3v|5F!)=B^;Gxwaksv_-#!k6`1>yLIavD@@fU-u6${0dXh8fTuz0MB9rS$A zb5MxehJ~ex96Km!)_n$W$*fPs**LuhN#F9?d-gsR0yIFF(sksZ?lA3kC;Q{w(H z5ud4d#9(F_8W!=d`@y#SQZKFiH=EO9cZ9f!VQl(iKX2<3?!Ss4wHO5I#`ZJE4v59X zECmuX`DyYbW8yN#u@buyg&0sU|D`JSH{u)lp+lVnb7kZ-<6&s9Tg+v42*&Z4@n&@O zXGlZUVi$4(w|Fqt`ty5J2KBFD_z$YE=sFB7ZWrHfEFX}qNUG{s7f?3Nisk9;Vp{rk zFbym$33~Bg?7J+^Tjc(=Eyow@W5PG4!2sfLUoV7MZGvKN!C=G!;S>LtLIw0Nwv+HHYdKsk~?cTv5cA{ zhaa_*qZW7FZpaQ!cj3o?r!J$U{k>BlfPo zt{V2w^RXzMij2lw$5wK1R;pPN4<-zT9U9L7L>W1DY!G*h_i1d2%o_kUCX(mX^piw`dX7b66%dzaI|JF8MYdaXe~|%4+`n0w4Op%*ezXcc7I{= zYayG-Iyy}2%b^QxV=ZYIhu1bHO*H;Bn2D;s67cCzjH2Ej$r^cHPPzvNQFNhD)Gst` zlwY997qH!N6dI7~332f%K0LuKd8jPh1D0$ucepQ*TB$w_CNx}5>nRw1e)CouW3NOw zEF*vqcJX+EVb093Pn=%XVOrq1!ran&iVM!!o113txV#02hHGM@K_SmJ!tydSO9`KEat8^<)OZH@g514N#g=<72M z_e@v!wt}rKoliAyZRu$XoT+(tch}ao=AF+J?0lxZb8novv#Y1KxwEIBXLoyNoYmd7 zyRD_Sr=Vk5dviy7XInwrv#rg0dfK|1ceZqH>uBpP=-JuT-CNh**;^3mq`9XkzAY5r z*|N8-S)6lQ+unlS?v`D&AVHB3!deL-nM6Z3*r{SunOSTs%Bfk-nQ1>u5L?rx9x4-)!s?U zSab7^?yfz%dkWfHTUvLvH3Ng@?v~CSZ3XJS2DmNm?X$fdTbtWDw}l5=pQ9zK@2Ph3 zw%z!4M_1>LI{Oho!gy6fzT`7o<7SW=^v|HvvD|>#-PW^*VeRVL)~0dqCf!CI-EA$~ zn!EROHZ#=i?K`Y!Ye!p4x81dO_Vl)N0835puB}|R?QPk%t-E0T#!uEgylh$BvgM2K zT)eby(fT@mcC~Hgr=`1f=h|KEyL(nBv9*0|=ZfXrb#^Tx(MoMSq!4f07H#k7YUw3G zR%>Kj8?rHDnZSM>T9<@HT2n_1ADa&Vex3~5#YUyZi=^1=&TU$q4Z`-2IJslm3c6R~h zw(dntVe3)Pe zDkph@YTdmwuG?B@-uZmVnSZtuf0O#y|39!ZweB?Hw&UdO#L{5nhJM<2xE*@frH;f!Tnv`FwB*z;z5( z4tVpATHyq((0|XK4yIBh-`v~sR9j~Ou-egPjGD=9-lI~w*}bQiF+r8h&n{cKbSZqU zr?-Gl-9jAOxWdxGt!J2_P_~De1yP&3yAT3Fsa>K{j9ewQckJoeSyZMV7g*P+ff}W8%Es6m3LP1*xIt9j%{t7P#DNk z&URxGz}83~PMX)K}BJzX7b%u91~%rl$!wjdap z-aH()?O}91t*rqGG|b+Xkg<(US_9kKds?=3v^7&Iq(K`A`ksPOTQ!PY{Fn)n2Oq0L zj07=7HM@mVjHtulgUrgS0(mroW?Oo8@p2#)k#Kk0_IBh{HyuFmc5Z_PcUubnA&J-B z-0{3&Y;y+~zE>%zo7Y;lJy)=E&-U%RT7)@Z-OlaJfhl)9&s=J7lvi1-*i83rQpX$>a~Qp45sqN}y{ zZry|O^SqRRy-*XH26?UG;M)y8+uC-6g%k*{aI(9d==x3{bw(V%^>41wN^?Bi$oo$efFuNP5?d^FQ4z0ZA-Ak?Twyu17 zMZvbNJ>XV>O>IxX*5+Y_t$J$SZa3}QT6VQOONq8;kz8~^bKTx)GfNNJckk`xVGD`^ z4~F*uY0%lzDn)ENLRk7~^Y)glJ(Lm~f;R#q2Hi6_O)v>2Y1b|&kU~SRgNs5y4FR%3 zJMHRhMQ8vA8x|7=ud$46s##B9qA0Cl@V(38YkoSnGqKw=roDqu>K^J-*Ph;HCOv+~ znlX(6e2+)nDh3=TYP(HTJRX~yt+4TCbRWGK=6Y*$N7oK!gg))sW4+tf@+?wptE%Z~ zgGFr%@EHV*U=)|$zOA+QZj#UK*}J@Z$5!|N`gkvs(Av}7ijvyf+}4c>@?3LIZ(GQO zz0t6co7Z+iJ6$`F{IE&XYe2V0h(e_WJ9{i4O>j3{_o;&CAR1bLJ3#uXKhTOa+`R?6 zx_Z&NngKQ9wO0s6+2zl*Zf#Y2u&=$EnH2@yq1GpNx9wKM-DaEx~DsgRNb{9hf2B!;n1_wdaqhryVPC5CBPeU8LXdCJO_Atp3KFxcX;O>psdlibnM>QB7m!iP}^Q- zLc+k9$Dt7hwnf=qq)PK7GMPsG zpqptzaPz3~yp>@*GCFaOJV)(jyTyb!q=Q664%|~?vyVGFIX83%uOA;D8|q`*FSTrR zRR)z^yYbCi*)Gn;R)Gm!Zozf{oUmL z-r#sPx|WERu4-3As@Ui%d&6BU8q!o@5Wv&33?FHqa)?@bcN??+kQl(paN4;V)K((k zmOXcEM+JA;q?a31lDFBdca7|ra;5anNnvKXo6cgc*d5%;zKRO%y2-9I#r?k7t~Ulw z8SEi@cI_~yRc*Y+QpT)_ckUTuWx=7n6*Yqhyh1NG>1B&k z_y%XNn}=(=WZT-eW0IY=_B=cMJ+(kAgTsh5gEz5{y=B+V$$OklT|uV@EfqFw<=C9{ zeHl!^GQ{R*!rQ{>w^2p-BGQRFSioHWr1~G1WFX;(O7UF^oA?w%R7g$-{>G-U8r2um z9_{_m{jDstL7`{|ev!D3tW_IQlNY3a)4dw!EsM7&Awv}zU)X8$)hho?uxZUdvc zCNP}pXu_qKSMPSV#EBa@@#;INVJG_HM0?oDj>aor+lajyZ#KzVu!BcbojH8N^(l;P0ksXwpKbDIJ94u ziag9B`%m~}g3R6*U3LvHXqP`xn32mCz8=ec8rQ&` zDS8wHnd1r0_1L}eATQU?Wh~oQD)%k$Z$zYbIYW*l^k@FnC;Md4*NXixJEkpnJ? zti6>|*gu<}Db$M#+3cw3_xL$}-)uZja=lO~RR?CE&*f(e_10Xb-?iiMCum78E#aoO z6lhzzv|RZ#GV0nT)mBFykiP?^@;+{W86PPJA3PS?B@(~uA-)pa-zc(J@E8YjAs%Pi-Gx2m!nT} zAK@pJdTXDUxlinDeepyiZ>Q+{T)ebT7d?YK;Tc%Ss`qBAvF}o+ z$O)^+Ip0^Rhq>%C&fzFyv=g={X<$xw%e-K5<5Degy+U8xt*Rm5ipV&Tvj z8;)-|2y$yGrT*Ue*1oy+!`ZC|^7{+>inFDea=jy$U6+{Vn@@>LnEdN5P&e~JqI)h= zPRqv^MgB`e^zWk_{UrDoq@Vh|A7v}P8)Nzs^k>z^m@fOYXRtP34?R=!Z64J&8*M{3 zw9wPmG}zqb_tNR4?AHm;xXNuA-Ocitd|K427oEsb8#wzl} z_Udmd&EhVazZfTlEm62>8hdOO`67ByrlXl+E~}>V;{@9Y?`F|O#tQ9oc!_(lIUPEv ztqTI$>}dE>2D|lC>Sbo2{rP=``Ql7zu64FOmpPVnqVqqK{|d?kPx3W<6Y?|CSB76% zHjJ-G9j~h5E2qR)X3G8ZtyHtGIM+T~s&|Ob&A}gbXyPgU25!Ddv2>kZ*GtE<(nX7u%*|(pZiR&;HEXGn|3Tm z;hPts*G5V`qhjN<&2yRciP{L@Lmg7)EoI8Q8jM{94@e!%mtpT*c3?K&C+l-Ox%%}5 z-xA(mjp*OAdrOO%T4FYFE;kM3Ye|()xhiG;l5%ewWnRyZV7#$Ql{xh-05sKz*a zy0^4~S{?ld3R8#kjGB1Gu6O3LQL3yuYN%zm4Wh#G0CQixFw3qed%|(5UigpbwVir` zv#hE8Gub}YEvJZZn5{x7yOTZ& ze!$mka7RelCkIQ_-r3T~eCu5MOxfE4x690X5o|mt#K&|Ty+FCi5vOCFS4Vn;QRwI{ zZTKy0lw*#ojxA)HH#B0P27lI-(yb3t_Rc!8nJc>86gOL#DaxMfF;zvZ8EPHlgWR(& zhn1OpFFPk&rPSWoNMwyK!82*|!kCRyD_=v`4EwHR9g=0z_J79nPI#nzQpbp}G}Q6V zWAHT3Jy!oj541t6zdxBLM7N29(6;({A`8{l6JPcM^vA61k;bySrT-5q4Hscbw6f+C zlReTuGJgCX!fnmido%lc{jD$eocP&#+>JgL+0e?~O<&1=O!g77#ftR^)&B32vh!*C zF**DCJ&)M$e4?xNf|}U-+my8TQuQETYG1y_})7FXZiLhejmE#sukwjOU;|vqp2nJskVlx5E=A| z$o%co%%RqwIdL25ZuAq{`vFza$SHD`Srr+F?}DD`);qV%n#t3U3A`{Gd%VZ*>j`H zWBcFZ!r>T9{yg@|^l6)OnTl3mW%o@}_L$V|o;MFQm)$RA%@=Z+u%YaMLCPM9%hsFA z9)z4J`g#K`d%f!XyG3Y}Wsh9yn=cH`6=z##+S$dj_D!KbF@Q5)m)_}8{)dloe-t~g zHucpDV#P_bL^1(~%KK5#OXe4C(M?|Kkz& z*u||Ai{`tg^C!BYu~u0>M9pPCf$WR?vU&W_KUX{*g-1eUP4h*z!;9RHsBCeDc(FJ7 z?-!B%>X@F(bXo18mj8oZ%A;G@C!f^_B-AXx_WxMGXR_ z`o;#8UFs8s`fHBLfC|Mez3>SLZ5Q|$Rp>?z~!DDqG_csKHUxOSTS z`=Bp@FE{!JeT>w~&w?qRxnTHE6l$E)@KNN6UwM5$2|mbLDvcHWKOKc%gr1!?`JabA z$nRT>z65<5TsHbwxpyCH-}ild)9O1Ph2K94gRk$uqwpm4dHpl6=|{_FI(%$R%V*X_ z;fnZymCw8c+?m2Z4=yKo^`C&H-#!0^DAYKd$-4=CE~MzM1)ophTfmH~xcqHCMrY;k zh(e9a8K%E97H63LTE9%!tuZ_og+D-CEbpVpe>R1GFAA?ipG=qW(?2f_v45Z8&-$2} z;V*!fDF3YCzl=hSnHm0S6l$Ez@EPitap>*wk6`SXxBkw2FA6nwX8iP*#>fo+I0`iu zrZ}6S|D^s!?f+~%Cbj>vFYqxi#(oUbUw>VLe_8u07tgWUUoBVrSdjAPuEJg?;5Yl{t_44q!t~$D(G2H}Yygt7Yg{OMJS6O@LUyUsp z|8M%3k>Tx8sIef!cOq{-CGT#q*wf2@ZxnuM32gIU?*1s;HV9s}^7Qx0Ln;2lJ{Dy3 zN1#UuJ^z&`)L4+w@sE|?N$9x~;JqpQMeuZjTi!(ZCH!;D$}_%KCKGz@39$69>7Qr5 z(fE<^e;fK(LeDY&S4LC#U%(?Nyb^^PZ_@I4*6)>SLeH-PZ%yG6SnT8LzdZ^y?quaV zq4%Ze;$OWf{6cUgg?|p*pTf-V8mBUOo1q^|(O=_ZQAU3w^qv&GpZJpKH)8a+`FNAz zktoy{lVS0XfmC_?L*q+EXFkwalHrILk<>S6c*e(!41WxK0s3QxAB{qd3mIm;)i{vh zKd1hwRQ;!-P-8zvKNE!->oL3xuEQT0rav{FWB5m4vDbOS7ot$(G>ThtJ}zVUdEis< zTYFm8M4`rCjJ_T${{6J!?kLpwis4s+SD;TDu0)~6O$;-BHAZ6itx>4)5W`!EWt5Zh zvflhn75}g5cyAHkbsw9*?)9+`EB}7%C-ry3&wi$*4qi&(k4D#Cl?R)@wk(2+Df}oH z7}Gx;UArc=UbnFR{xA%J>tz2U^1lTA$M9zie+}FXK4thUSo+`7|2YaZHe>oS-Zai) z_&lDu`E<8U9HI`!dMc^gm+xk-I@-Y*mZ}c$}!}O2FObpW>8XGape5$b! z!^7Z3!w>kFhvC^M)HsLXhoeyA9EREdXq-c_^!F*+>({Ho zqujfX_IKg)KJH=VPtspy7_2`Fe-G|V;cvkI4EVV5pM$<8MSljoE`|Rs3N=1r{LexU z6Z)za@bxL&3hqkb=YiL!F!P_rQdHh5`b%RchMC_qUSjyhDAf3f;hreen26zDj>3b8 z&lC+0M4`q#3|FI2;~IwFfj;7o=C7-m&oq`{^!t3=!tjT|{lahf0Ofm9Q*;?G zj$i$K74w0>qqfr zQK)eMlYdhb>T|#0*MpbgxB0%v`lHYBMrVH0=k`ROubhT|$@F1-eb@Qd^IH|?lt+$XZae~ z%l|vd9|f;5dDy>w8QgF6{{!_O1N-{F7lmu*4U2s2zqFXbjGwLjhM9L)2NoYFB42O^ z*zFGtUyJ-B@aI*()f>=11ovwFtJyE=J4S}tA9hSbUuXC&*w2kWEB_nF?}aY%q`qCe zi`4^eH~vZZyN!-LSHFk-a#iT?W53n+^KQ&EI5K|L_wR;auipal#U37iG7@Qg%C3J_ zf0lP#ia=j}3I2Yt*9UvA6?+Rm_FMg(=*3r64U0ak7i+(Ozxww5JI~iLK8mK#v$Vep zJfOI>Kzt^G|G42RsZZpYey#X3h!6GQa;raO_yYXkR{T3B`i)unE&kma!#DHJn6#&C z7<(7QKl==`|6bbz-ePz=_Sy{g^^dWhi+r$`=`Pv)pr^F3IEQT;crLbql@xxm*I2hKP>{V5B<@~{BlJP z(ChOf?6U;6@xs5Igx_BTTl?BtvG+&{U)|WhZ7;&7N({ANszRwx_Med{;}+@$d9_ZF|tagJt~llwXA3 z`nT-}^LrI+`m}x8{7Eq5sqJ(4<1*y+R{jHx{@eB?`eO@p^M|%G_><@}YW!!>2mki= zZu{4ieEh%dJmrPIQ~BHT(2s-Fej3CaCslH6d^>Nij*!naB#D(iAI-g&N?Ix}{wC?& zp2&;BnhxrJh!a5l4?Zi>XB{T_iZ1nW!$y~UNWg^*4wv01S4|g8CnP56gg)6&69UsI zhnEV{rV;?-3_rPXnSCzp(ZAm8Gt-h(vLuI&yI_Rm5mLkSC1Y-U0-B`U`INDAuH6P2 zvU`%G>>7kIfv+7twJ2X6f9 z?LIv&Nt8pXa=FSRCpDGIWjR);r#$KWtaQ>`oJC~~X0}Ranx!+@(phJzY_2#H59>=p z05cTXc9QVLNVS|fy4b6cB-J4!m0)MtVK}iD5GVP?iDKMPhv?)5#|{=}kGPyFeVsqf z&D!WPpj>jtCd~kf(~%@Y#AT@@Sx%|6pd?!+m3Eb6wj}vmmP2FtGN~Murom&0GpU@N zIH$&?fVspNQn#9l`BbDNwM$cS(g`e0MJz8WPLN76rmRNyL!1r~XQ4D^e3mdMc(r8M_+*xJPD(ljCQh;O z9-8EvFkp6QS_xH2nuw;INbX81O{6g&WP;q}BvZttkVuw_KltLJGhb4P@SIR%r$*R` z5JNjjry0I%-W|w$n=Na1B;GRt0}V5GhZj{JRWgF+zOyfE3mQf7xldlPXjSdlfy_NZ1>W zDH_`84Cb`a`B8+p{n<`aLCWX}EAGx6vSa5GvGsEY{#ftcIeZ6u##Ax2ikOllzm!Ax zlM%F>90wwz<5PRw;VJ&qC2fIg7J~3wJ+wnDf*U#ubI8Z;iw+Z#mdJSzA{$NOV}!J5 ze1eg9FsyQlkne4GZiJaGPTNY3I#IRVw$j(`JscI~NRC)LJ<0|};`2!8t@ywR>&R{6 zlar*v4efBF!YkoA&5UWsK}n0`T$2WOa8(TL+{R#3m6Ky@q+5ev!|r?Tl)SkO%#nH> z^>=!_hI4@p6XUM>4fCOI9{~TUXX5Jk{udB=CAk0q literal 308876 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

wvpHe==P#cXtfcjPzJBiBEQu$ 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 4 * is an R4400, which is the same rule IRIX and Linux use, and is why IRIS * reports PRId 0x0440. + * + * The R16000 has no imp of its own: it reports the R14000's 0x0f and is told + * apart by revision, major >= 3 (Linux's cpu-probe.c tests major > 2 under + * PRID_IMP_R14000). */ #define IMP_R4000 0x04 /* R4400 too — see PRID_REV_MAJOR */ #define IMP_R4400 0x04 diff --git a/docs/o2-ip32.md b/docs/o2-ip32.md index a1ee2daf5..0dba72c24 100644 --- a/docs/o2-ip32.md +++ b/docs/o2-ip32.md @@ -3,8 +3,8 @@ The O2 is SGI's unified-memory workstation: CRIME (the memory controller and rendering engine), MACE (the I/O chip: PCI, Ethernet, serial ports, PS/2, audio, the clocks) and GBE (the display engine, which scans the frame buffer -out of main memory). IRIS emulates it with an R10000 or an R5000, chosen at run -time like the other machines. +out of main memory). IRIS emulates it with an R5000, R10000 or R12000, chosen at +run time like the other machines. It runs IRIX 6.5 (tested with 6.5.22) to the desktop, with networking, audio, SCSI disks and CD-ROMs, X and OpenGL through the CRIME rendering engine, and @@ -28,7 +28,7 @@ serial_log = "serial.log" [machine] profile = "o2_ip32" -cpu = "r10000" # or "r5000" +cpu = "r10000" # or "r5000" or "r12000" [o2] control_port = 2293 @@ -65,14 +65,18 @@ in the file to silence the note. ## CPU, memory and clock -- **R10000 and R5000** both run the shadow cache model that IP28 uses, from +- **R5000, R10000 and R12000** all run the shadow cache model that IP28 uses, from reset: loads and stores go straight to memory. The PROM tests physical page 0 uncached while its stack sits in cache tags for that same page, so while those tags stand the bus answers for the page from a separate 4 KB page. - Linux supports only R5000-class O2s. - `[clock] fixed_mhz` is CP0 Count, 90 MHz unless set; the PROM measures and reports twice it as the CPU clock. R10000 O2s shipped at 175 and 195 MHz - (87.5 and 97.5), R5000s at 180 to 300. + (87.5 and 97.5), R5000s at 180 to 300. The R12000 (revision 3.5, 2 MB secondary + cache) shipped at 400 MHz; it defaults to 200 MHz Count (400 MHz). Its + secondary cache has 64-byte lines like the R10000's, because the PROM fails + with 128-byte ones. The 270 and 300 MHz revision 2.3 part (1 MB) is not + offered. - `banks` is the kit in each of the four DIMM pairs from A: 32, 64, 128 or 256 MB each, largest first, up to 1 GB. The default `[128, 128]` is 256 MB. IRIX boots with any of them, from a single 32 MB kit up. NetBSD's 32-bit diff --git a/docs/octane-ip30.md b/docs/octane-ip30.md index cc652a8e2..0798d29ee 100644 --- a/docs/octane-ip30.md +++ b/docs/octane-ip30.md @@ -59,9 +59,11 @@ overlay = true ``` Paths are relative to the directory iris runs in. Every key is listed in -[FEATURES.md](../FEATURES.md). `machine.cpu` must be `r10000`. `[clock] -fixed_mhz` sets CP0 Count; unset it is 97.5 MHz, half of the R10000's -195 MHz pipeline clock. +[FEATURES.md](../FEATURES.md). `machine.cpu` is `r10000` (revision 2.7), +`r12000` (revision 3.5, 2 MB secondary cache) or `r14000` (revision 2.4, 2 MB). +`[clock] fixed_mhz` sets CP0 Count, half the pipeline clock. Unset it is +97.5 MHz for the 195 MHz R10000, 180 MHz for a 360 MHz R12000 and 300 MHz for a +600 MHz R14000. ## PROM and flash diff --git a/src/bin/iris_bench.rs b/src/bin/iris_bench.rs index d26f4a3cd..ca28d9742 100644 --- a/src/bin/iris_bench.rs +++ b/src/bin/iris_bench.rs @@ -270,6 +270,11 @@ const CELLS: &[Cell] = &[ Cell { name: "r5000-jitv2", features: "jitv2", cpu: "r5000", expect_cpu: "R5000" }, Cell { name: "r4400-lightning", features: "lightning", cpu: "r4400", expect_cpu: "R4400" }, Cell { name: "r4400-jitv2-lightning", features: "jitv2,lightning", cpu: "r4400", expect_cpu: "R4400" }, + // The R10000 family. It always runs the shadow caches, so the default + // build covers it. + Cell { name: "r10000-interp", features: "", cpu: "r10000", expect_cpu: "R10000" }, + Cell { name: "r12000-interp", features: "", cpu: "r12000", expect_cpu: "R12000" }, + Cell { name: "r14000-interp", features: "", cpu: "r14000", expect_cpu: "R14000" }, ]; fn build_cell(cell: &Cell, root: &Path, force: bool) -> Result { @@ -1077,12 +1082,19 @@ mod tests { #[test] fn every_cell_name_is_unique_and_maps_to_a_cpu() { for (i, a) in CELLS.iter().enumerate() { - assert!(a.expect_cpu == "R4400" || a.expect_cpu == "R5000"); + assert!(["R4400", "R5000", "R10000", "R12000", "R14000"].contains(&a.expect_cpu)); // `expect_cpu` is what the `matrix` guard compares the guest's // `#machine cpu=` line against, so it must describe the `--cpu` // this cell actually passes. CPU is a runtime flag (see `Cell::cpu`), // not a cargo feature, so the two agreeing is the whole contract. - let want = match a.cpu { "r4400" => "R4400", "r5000" => "R5000", c => panic!("{}: unknown --cpu {}", a.name, c) }; + let want = match a.cpu { + "r4400" => "R4400", + "r5000" => "R5000", + "r10000" => "R10000", + "r12000" => "R12000", + "r14000" => "R14000", + c => panic!("{}: unknown --cpu {}", a.name, c), + }; assert_eq!(a.expect_cpu, want, "{}", a.name); for b in CELLS.iter().skip(i + 1) { assert_ne!(a.name, b.name); } } diff --git a/src/config.rs b/src/config.rs index b3bb7fddd..02f02f97c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -707,12 +707,17 @@ impl MachineProfile { } /// Whether this profile can have `cpu`, and why not if it cannot. The - /// Octane builds only the part below; the O2 constructor still refuses - /// its own, after `validate()`. + /// Octane takes an R10000, R12000 or R14000 and the IP28 an R10000; the + /// O2 constructor still refuses its own, after `validate()`. pub fn accepts_cpu(self, cpu: CpuModel) -> Result<(), String> { match self { - Self::OctaneIp30 if cpu != CpuModel::R10000 => { - Err("an Octane has an R10000 ([machine] cpu = \"r10000\")".into()) + Self::OctaneIp30 if !matches!(cpu, CpuModel::R10000 | CpuModel::R12000 | CpuModel::R14000) => Err( + "an Octane has an R10000, R12000 or R14000 ([machine] cpu = \"r10000\", \"r12000\" or \"r14000\")".into(), + ), + Self::Indigo2Ip28 + if matches!(cpu, CpuModel::R12000 | CpuModel::R14000) => + { + Err("an Indigo2 IMPACT (IP28) has an R10000 ([machine] cpu = \"r10000\")".into()) } _ => Ok(()), } @@ -761,17 +766,18 @@ impl MachineProfile { matches!(self, Self::IndyIp24) } - /// The CPU models this machine can be built with. The O2 has an R5000 or - /// an R10000 (an R4400 is refused when the machine is built, not by - /// `validate()`); the Octane shipped only with the 195 MHz R10000; the - /// Indy and the Indigo2 take any of the three. + /// The CPU models this machine can be built with. The O2 has an R5000, + /// an R10000 or an R12000 (the others are refused when the machine is + /// built, not by `validate()`); the Octane has an R10000, R12000 or + /// R14000; the Indy and the Indigo2 take any part, except that the IP28 + /// is refused anything but the R10000 by `validate()`. /// /// Single source of truth for the front-ends' Processor pickers, so they /// cannot offer a CPU the machine will refuse. pub fn cpus(self) -> &'static [CpuModel] { match self { - Self::OctaneIp30 => &[CpuModel::R10000], - Self::O2Ip32 => &[CpuModel::R5000, CpuModel::R10000], + Self::OctaneIp30 => &[CpuModel::R10000, CpuModel::R12000, CpuModel::R14000], + Self::O2Ip32 => &[CpuModel::R5000, CpuModel::R10000, CpuModel::R12000], _ => &CpuModel::ALL, } } @@ -1050,16 +1056,29 @@ pub enum CpuModel { /// the Indigo2 IMPACT (IP28). The machine uses shadow cache arrays; /// see `docs/indigo2-ip28.md` and `src/cpu/mips_cache_shadow.rs`. R10000, + /// MIPS R12000: the R10000's programming model. The Octane and the O2 + /// have it as revision 3.5 with a 2 MB secondary cache. + R12000, + /// MIPS R14000, revision 2.4, with a 2 MB secondary cache. Selectable on + /// the Octane. + R14000, } impl CpuModel { - pub const ALL: [Self; 3] = [Self::R4400, Self::R5000, Self::R10000]; + pub const ALL: [Self; 5] = [Self::R4400, Self::R5000, Self::R10000, Self::R12000, Self::R14000]; + + /// Whether the part is in the R10000 family. + pub fn is_r10000_family(self) -> bool { + matches!(self, Self::R10000 | Self::R12000 | Self::R14000) + } pub fn label(self) -> &'static str { match self { Self::R4400 => "MIPS R4400", Self::R5000 => "MIPS R5000", Self::R10000 => "MIPS R10000", + Self::R12000 => "MIPS R12000", + Self::R14000 => "MIPS R14000", } } } @@ -1075,7 +1094,7 @@ impl CpuModel { /// need no tag check against it. /// - `auto`: `shadow` in a `jitv2` build, `full` otherwise. /// -/// The R10000 (IP28) only has the shadow model. +/// The R10000 family only has the shadow model. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default, clap::ValueEnum)] #[serde(rename_all = "snake_case")] #[clap(rename_all = "lower")] @@ -1090,7 +1109,7 @@ impl CacheModel { /// Whether `cpu` runs the shadow cache under this setting. pub fn is_shadow(self, cpu: CpuModel) -> bool { match (cpu, self) { - (CpuModel::R10000, _) => true, + (cpu, _) if cpu.is_r10000_family() => true, (_, Self::Full) => false, (_, Self::Shadow) => true, (_, Self::Auto) => cfg!(feature = "jitv2"), @@ -2735,16 +2754,18 @@ pub struct Cli { #[arg(long = "no-scsi-deferred-int", default_value_t = false)] pub no_scsi_deferred_int: bool, - /// Emulated CPU: `r4400` (default), `r5000`, or `r10000`. Overrides `[machine] cpu`. + /// Emulated CPU: `r4400` (default), `r5000`, `r10000`, `r12000` or `r14000`. Overrides `[machine] cpu`. /// - /// All three models are compiled into every build — each is its own + /// Every model is compiled into every build — each is its own /// monomorphisation, so the hot path carries no per-model branch — and this /// picks between them at construction. The `r5k` Cargo feature is removed. + /// The Octane takes `r10000`, `r12000` and `r14000`; the O2 `r5000`, + /// `r10000` and `r12000`; the IP28 `r10000`. #[arg(long = "cpu", value_name = "MODEL")] pub cpu: Option, /// Cache model: `auto` (default: `shadow` in a jitv2 build, else `full`), - /// `full` or `shadow`. Overrides `[machine] cache`. The R10000 is always + /// `full` or `shadow`. Overrides `[machine] cache`. The R10000 family is always /// `shadow`. #[arg(long = "cache", value_name = "MODEL")] pub cache: Option, @@ -3466,8 +3487,8 @@ mod export_tests { #[test] fn a_profile_says_which_processors_it_accepts() { let accepted = |p: MachineProfile| CpuModel::ALL.into_iter().filter(|&c| p.accepts_cpu(c).is_ok()).collect::>(); - assert_eq!(accepted(MachineProfile::OctaneIp30), [CpuModel::R10000]); - assert_eq!(accepted(MachineProfile::IndyIp24), [CpuModel::R4400, CpuModel::R5000, CpuModel::R10000]); + assert_eq!(accepted(MachineProfile::OctaneIp30), [CpuModel::R10000, CpuModel::R12000, CpuModel::R14000]); + assert_eq!(accepted(MachineProfile::IndyIp24), CpuModel::ALL); // The counts are what the checks in validate() and the Octane // constructor allowed before they moved here: one on every machine @@ -3551,6 +3572,58 @@ mod export_tests { assert_eq!(back.serial_socket_a.as_deref(), Some("/run/x.sock")); } + /// `cpu` names each part, and the R10000 family runs the shadow caches. + #[test] + fn every_cpu_part_is_selectable_by_name() { + for (name, cpu, family) in [ + ("r4400", CpuModel::R4400, false), + ("r5000", CpuModel::R5000, false), + ("r10000", CpuModel::R10000, true), + ("r12000", CpuModel::R12000, true), + ("r14000", CpuModel::R14000, true), + ] { + let cfg: MachineConfig = toml::from_str(&format!("[machine]\ncpu = \"{name}\"\n")).unwrap(); + assert_eq!(cfg.machine.cpu, cpu, "{name}"); + assert_eq!(cpu.is_r10000_family(), family, "{name}"); + assert_eq!(CacheModel::Full.is_shadow(cpu), family, "{name}"); + assert!(CpuModel::ALL.contains(&cpu), "{name}"); + } + } + + /// The IP28 shipped with the R10000 only, so it refuses the later family + /// parts; the Octane and the O2 each name the parts they take. + #[test] + fn machines_name_the_cpus_they_accept() { + let mut cfg = MachineConfig::default(); + cfg.machine.profile = MachineProfile::Indigo2Ip28; + for cpu in [CpuModel::R12000, CpuModel::R14000] { + cfg.machine.cpu = cpu; + let err = cfg.validate().expect_err("the IP28 has an R10000"); + assert_eq!(err, "an Indigo2 IMPACT (IP28) has an R10000 ([machine] cpu = \"r10000\")"); + } + cfg.machine.cpu = CpuModel::R10000; + cfg.validate().expect("the IP28 takes the R10000"); + + // Both machines check the part before they look for a PROM. + let refusal = |profile, cpu| { + let mut cfg = MachineConfig::default(); + cfg.machine.profile = profile; + cfg.machine.cpu = cpu; + match profile { + MachineProfile::OctaneIp30 => crate::ip30_machine::OctaneMachine::new(&cfg).err(), + _ => crate::ip32_machine::O2Machine::new(&cfg).err(), + } + }; + let octane = "an Octane has an R10000, R12000 or R14000 ([machine] cpu = \"r10000\", \"r12000\" or \"r14000\")"; + let o2 = "an O2 has an R5000, R10000 or R12000 ([machine] cpu = \"r5000\", \"r10000\" or \"r12000\")"; + for cpu in [CpuModel::R4400, CpuModel::R5000] { + assert_eq!(refusal(MachineProfile::OctaneIp30, cpu).as_deref(), Some(octane), "{cpu:?}"); + } + for cpu in [CpuModel::R4400, CpuModel::R14000] { + assert_eq!(refusal(MachineProfile::O2Ip32, cpu).as_deref(), Some(o2), "{cpu:?}"); + } + } + /// Every old `[o2]` key lands on the shared key it stood for, and the /// section keeps only what is the O2's alone. #[test] diff --git a/src/cpu/jitv2/equiv_test.rs b/src/cpu/jitv2/equiv_test.rs index ea580594b..6a2eea1c1 100644 --- a/src/cpu/jitv2/equiv_test.rs +++ b/src/cpu/jitv2/equiv_test.rs @@ -4433,15 +4433,15 @@ mod tests { (CoreSnapshot::capture(&interp.core), CoreSnapshot::capture(&jit.core)) } - /// The R10000 keeps bits 63:32 on a partial LWR while 64-bit operations are - /// enabled for the current mode and the R5000 sign-extends; with them off - /// (a 32-bit user process, UX=0) the R10000 sign-extends too. The JIT and - /// the interpreter must agree at every offset in every mode, and the - /// interpreter's result is the one `partial_lwr_keeps_the_upper_word_only_on_the_r10000` - /// pins. - #[test] - fn jit_lwr_matches_the_interpreter_on_the_r10000_and_r5000() { - use crate::cpu::mips_cache_shadow::{R10000ShadowCache, R5000ShadowCache}; + /// The R10000 family keeps bits 63:32 on a partial LWR while 64-bit + /// operations are enabled for the current mode and the R5000 sign-extends; + /// with them off (a 32-bit user process, UX=0) the family sign-extends too. + /// The JIT and the interpreter must agree at every offset in every mode, and + /// the interpreter's result is the one + /// `partial_lwr_keeps_the_upper_word_on_the_r10000_family` pins. + #[test] + fn jit_lwr_matches_the_interpreter_on_the_r10000_family_and_r5000() { + use crate::cpu::mips_cache_shadow::{R10000ShadowCache, R12000ShadowCache, R5000ShadowCache}; fn check>>(model_keeps_upper: bool) { use crate::cpu::mips_core::{STATUS_ERL, STATUS_EXL, STATUS_KX, STATUS_SX, STATUS_UX}; const RESERVED: u32 = 3 << 3; @@ -4483,6 +4483,7 @@ mod tests { } } check::(true); + check::(true); check::(false); } @@ -8016,7 +8017,7 @@ mod tests { /// masked-store helper), and the instructions after it run. The same access /// as a load, and a store on the R5000, still fault in both engines. #[test] - fn refused_uncached_store_matches_the_interpreter_on_the_r10000_and_r5000() { + fn refused_uncached_store_matches_the_interpreter_on_the_r10000_family_and_r5000() { use crate::cpu::mips_cache_v2::{R10000Cache, R5000Cache, CpuModel}; use crate::cpu::mips_core::STATUS_EXL; use crate::cpu::mips_isa::{OP_ADDIU, OP_LW, OP_SW, OP_SWL}; diff --git a/src/cpu/mips_cache_shadow.rs b/src/cpu/mips_cache_shadow.rs index 6202335de..0d7100e43 100644 --- a/src/cpu/mips_cache_shadow.rs +++ b/src/cpu/mips_cache_shadow.rs @@ -36,7 +36,7 @@ use std::sync::Arc; use crate::cpu::mips_cache_v2::{ cache_op_name, model, r4k_load_taglo, r4k_store_taglo, CpuModel, FetchInstrResult, MipsCache, - C_ILT, C_IST, C_R10K_CBARRIER, C_R10K_ILD, C_R10K_ISD, CACH_PD, CACH_PI, CACH_SD, CACH_SI, + C_ILT, C_IST, C_IWBINV, C_R10K_CBARRIER, C_R10K_ILD, C_R10K_ISD, CACH_PD, CACH_PI, CACH_SD, CACH_SI, }; use crate::traits::{BusDevice, BusRead64, BUS_OK}; use crate::devlog::{LogModule, CACHE_LOG_HIT, CACHE_LOG_OP, devlog_is_active, devlog_mask}; @@ -189,8 +189,12 @@ impl< const FIR: u32, const TLB_ENTRIES: usize, const MODEL: u8, > ShadowCache { - const R10K: bool = MODEL == model::R10000; + const R10K: bool = model::r10k_family(MODEL); const R5K: bool = MODEL == model::R5000; + /// Index Writeback Invalidate (D) also zeroes the primary data tag on the + /// R12000 and later; the R10000 leaves it as it was. NEC VR12000 user's + /// manual, Appendix B.20. The R14000 is taken to match. + const IWBI_CLEARS_PD_TAG: bool = Self::R10K && MODEL != model::R10000; const IC_LINES: usize = if IC_LINE == 0 { 0 } else { IC_SIZE / IC_LINE }; const DC_LINES: usize = if DC_LINE == 0 { 0 } else { DC_SIZE / DC_LINE }; const L2_LINES: usize = if L2_LINE == 0 { 0 } else { L2_SIZE / L2_LINE }; @@ -367,11 +371,10 @@ impl< const PRID: u32 = PRID; const FIR: u32 = FIR; const TLB_ENTRIES: usize = TLB_ENTRIES; - // The R10000 implements 44 virtual address bits where the R4x00 implements - // 40; the shadow cache is only used for it, but key this off the same flag - // that selects its cache encodings rather than asserting it unconditionally. - const VA_BITS: u32 = if MODEL == model::R10000 { 44 } else { 40 }; - const PA_BITS: u32 = if MODEL == model::R10000 { 40 } else { 36 }; + // The R10000 family implements 44 virtual address bits where the R4x00 + // implements 40. + const VA_BITS: u32 = if Self::R10K { 44 } else { 40 }; + const PA_BITS: u32 = if Self::R10K { 40 } else { 36 }; // The CPU's name, which snapshots check: the same as the full model's, so // a mismatch reads as a cache-kind difference rather than a different CPU. // The R10000 keeps its historical "shadow", which existing IP28 @@ -379,11 +382,12 @@ impl< const NAME: &'static str = match MODEL { model::R4400 => "R4400", model::R5000 => "R5000", + model::R12000 => "R12000", _ => "shadow", }; const CACHE_KIND: &'static str = "shadow"; const R10K_FAMILY: bool = Self::R10K_CACHE_OPS; - const R10K_CACHE_OPS: bool = MODEL == model::R10000; + const R10K_CACHE_OPS: bool = Self::R10K; const SECONDARY_TAG_MASK: u64 = if Self::R10K_CACHE_OPS { R10K_L2_TAG_MASK } else { u64::MAX }; } @@ -665,6 +669,15 @@ impl< 0 } + C_IWBINV if Self::IWBI_CLEARS_PD_TAG && sel == CACH_PD => { + let idx = self.tag_slot(sel, virt_addr); + let s = self.shadow(sel); + if idx < s.tags.len() { + s.tags[idx] = 0; + } + 0 + } + // Invalidate, writeback, fill, and the R4000 hit operations. All // no-ops: there is nothing held that could be stale or dirty. _ => 0, @@ -765,6 +778,27 @@ impl< pub type R10000ShadowCache = ShadowCache<32768, 64, 32768, 32, 1048576, 128, true, 0x0000_0925, 0x0000_0900, 64, { model::R10000 }>; +/// R12000 3.5 as the Octane has it: the R10000's programming model with a +/// 2 MB secondary cache. PRId 0x0e35, FIR 0x900, 128-byte secondary lines +/// (SB: a model choice). +/// +/// The Octane's R14000 is this type with `R14000_PRID` set at runtime, as the +/// Octane's own R10000 revision is; only the PRId differs. Both report +/// "R12000" as `NAME`. +pub type R12000ShadowCache = + ShadowCache<32768, 64, 32768, 32, 2097152, 128, true, 0x0000_0e35, 0x0000_0900, 64, { model::R12000 }>; + +/// PRId of the R14000 2.4 in the Octane, to set on an `R12000ShadowCache`. +pub const R14000_PRID: u32 = 0x0000_0f24; + +/// R12000 3.5 as the O2 has it: the Octane part with 64-byte secondary lines +/// (SB clear). With 128-byte lines the O2 PROM panics before its banner +/// (write TLB miss at 0x0); 64 boots. IRIX on the O2 never reads SB and sizes +/// the secondary cache as 512 KB << SS. +pub type R12000O2ShadowCache = + ShadowCache<32768, 64, 32768, 32, 2097152, 64, true, 0x0000_0e35, 0x0000_0900, 64, { model::R12000 }>; + + /// SGI O2 R10000 (IP32): the IP28 model with 64-byte secondary-cache lines. /// /// The O2 PROM (4.18 and earlier) handles only that line size. With Config's @@ -986,6 +1020,25 @@ mod tests { assert_eq!(c.read::<4>(0, 0x2000).data, 0x1234_5678); } + /// On the R12000 and later Index Writeback Invalidate (D) zeroes the + /// line's primary data tag, which Index Load Tag then reads back; the + /// R10000 keeps the tag. + #[test] + fn index_writeback_invalidate_d_clears_the_tag_from_the_r12000_on() { + fn run>>() -> u64 { + let mem: Arc = Arc::new(Memory::new(1)); + let c = C::from(mem); + let tag = 0x0000_0001_2345_6780u64; + c.cache_op(crate::cpu::mips_cache_v2::C_IST | CACH_PD, 0x40, tag); + assert_eq!(c.cache_op(crate::cpu::mips_cache_v2::C_ILT | CACH_PD, 0x40, 0), tag); + c.cache_op(crate::cpu::mips_cache_v2::C_IWBINV | CACH_PD, 0x40, 0); + c.cache_op(crate::cpu::mips_cache_v2::C_ILT | CACH_PD, 0x40, 0) + } + assert_eq!(run::(), 0); + assert_eq!(run::(), 0); + assert_eq!(run::(), 0x0000_0001_2345_6780); + } + /// Geometry is what CP0 Config is built from, so it must be the real /// part's even though the model holds nothing. #[test] diff --git a/src/cpu/mips_cache_v2.rs b/src/cpu/mips_cache_v2.rs index 6cdeb67be..1556b6ae5 100644 --- a/src/cpu/mips_cache_v2.rs +++ b/src/cpu/mips_cache_v2.rs @@ -631,8 +631,8 @@ pub trait CpuModel: MipsCache { /// The part is in the R10000 family, which shares one programming model: /// FrameMask, and 44 virtual and 40 physical address bits. /// Established for the R10000. The R12000 is inferred to match: its manual's - /// list of changes from the R10000 has no TLB or CP0 change. The R14000 and - /// R16000 are a model choice that gives them the same TLB. + /// list of changes from the R10000 has no TLB or CP0 change. The R14000 is + /// a model choice that gives it the same TLB. const R10K_FAMILY: bool = false; /// A partial LWR keeps bits 63:32 of the destination. Observed on the /// R10000; whether the later parts do the same is not established, so they @@ -1469,6 +1469,13 @@ pub mod model { pub const R4400: u8 = 0; pub const R5000: u8 = 1; pub const R10000: u8 = 2; + pub const R12000: u8 = 3; + + /// The R10000 family: the R10000 and the parts that follow it, which share + /// one programming model. + pub const fn r10k_family(model: u8) -> bool { + matches!(model, R10000 | R12000) + } } /// SGI Indy R4400: direct-mapped 16K L1s, 1 MB unified L2 owning the decode slots. diff --git a/src/cpu/mips_exec.rs b/src/cpu/mips_exec.rs index 5b72aade4..4e38e734e 100644 --- a/src/cpu/mips_exec.rs +++ b/src/cpu/mips_exec.rs @@ -2327,15 +2327,10 @@ impl MipsExecutor { c |= log2(32768) << 26; // 32 KB L1D c |= 1 << 15; // big endian if C::L2_LINE == 128 { c |= 1 << 13; } - // Secondary cache size. The encoding is not in anything to hand, - // so it was swept against the PROM rather than guessed. - // - // 1 is the value to keep: IRIX reports "Secondary unified - // instruction/data cache size: 1 Mbyte", which agrees with this - // model's own `L2_SIZE`, and the PROM's power-on diagnostics pass - // and IRIX boots with it. 4 also passes POST but has IRIX report - // 8 MB, contradicting the model. - c |= 1 << 16; + // SS is log2(secondary cache size / 512 KB): 0 is 512 KB, 1 is 1 MB, + // 2 is 2 MB, up to 5 for 16 MB (NEC U10278EJ4V0UM p.230). It follows + // the model's own `L2_SIZE`. EC, SC, DN, PM, DSD and SK stay zero. + c |= (C::L2_SIZE / (512 << 10)).trailing_zeros() << 16; c |= 2; // K0 = uncached at reset config = c; } @@ -4751,7 +4746,7 @@ va={:#018x} phys={:#010x} (code pfn {:#x}, page {:#010x}, word {}/{})", const EH_REGION: u64 = 0xC000_0000_0000_0000; // VPN2 is bits 43:13 on the R10000 family (R10000 UM pp. 219, 288) and // 39:13 on the R4x00 and R5000. The R12000 is inferred to match (its - // manual lists no TLB change); the R14000 and R16000 are a model choice + // manual lists no TLB change); the R14000 is a model choice // that follows the same width. let eh_vpn2_64 = crate::cpu::mips_tlb::vpn2_mask(C::VA_BITS); diff --git a/src/cpu/mips_exec_test.rs b/src/cpu/mips_exec_test.rs index 75c11ab4f..d7f862e24 100644 --- a/src/cpu/mips_exec_test.rs +++ b/src/cpu/mips_exec_test.rs @@ -6802,9 +6802,9 @@ mod tests { .unwrap().join().unwrap(); } - /// A partial LWR keeps bits 63:32 of the destination on the R10000 while - /// 64-bit operations are enabled for the current mode, and sign-extends on - /// the R4400 and R5000 and on the R10000 when they are off (a 32-bit user + /// A partial LWR keeps bits 63:32 of the destination on the R10000 family + /// while 64-bit operations are enabled for the current mode, and sign-extends + /// on the R4400 and R5000 and on the family when they are off (a 32-bit user /// process, UX=0); a complete word sign-extends on all. /// Compiled LWR reads `core.lwr_upper_below` rather than decoding Status, /// so it must follow `is_64bit_mode()` through a Status write and through @@ -6836,7 +6836,7 @@ mod tests { } #[test] - fn partial_lwr_keeps_the_upper_word_only_on_the_r10000() { + fn partial_lwr_keeps_the_upper_word_on_the_r10000_family() { use crate::cpu::mips_core::{STATUS_KX, STATUS_SX, STATUS_UX}; const USER: u32 = 2 << 3; const SUPER: u32 = 1 << 3; @@ -6874,5 +6874,58 @@ mod tests { check::(false); check::(false); check::(true); + check::(true); + } + + /// Config reports each part's secondary cache: SS (bits 18:16) is + /// log2(secondary size / 512 KB) and SB (bit 13) is set for 128-byte lines + /// (NEC U10278EJ4V0UM p.230). The primary caches read 32 KB. + #[test] + fn config_reports_the_secondary_cache_of_each_family_part() { + use crate::cpu::mips_cache_shadow::*; + fn config>>() -> u64 { + let cfg = MipsCpuConfig::for_model::(Arc::new(crate::ip22_bus::memory_map(false))); + let mut exec = Box::new(MipsExecutor::::new( + Arc::new(MockMemory::new()), PassthroughTlb::default(), &cfg)); + disable_jitv2(&mut exec); + exec.core.read_cp0(16) + } + // The executor is large; build it on a thread with room. + std::thread::Builder::new().stack_size(16 * 1024 * 1024).spawn(|| { + for (name, c, ss, sb) in [ + ("R10000", config::(), 1, 1), + ("R12000", config::(), 2, 1), + ("R12000 O2", config::(), 2, 0), + ] { + assert_eq!(c >> 26, 0b011_011, "{name}: IC and DC read 32 KB"); + assert_eq!(c & 0x03FF_FFFF, (ss << 16) | (sb << 13) | 0x8000 | 2, "{name}: Config {c:#x}"); + } + }).unwrap().join().unwrap(); + } + + /// A TLB write on an R12000 with FrameMask set clears EntryLo bit 18, as on + /// the R10000. + #[test] + fn framemask_clears_entrylo_bits_on_the_r12000() { + use crate::cpu::mips_cache_shadow::*; + // Write the entry with FrameMask set, find it with TLBP, clear EntryLo0 + // and TLBR it: (FrameMask, EntryLo0 as the TLB holds it, physical page). + fn written>>() -> (u64, u64, u64) { + const VA: u64 = 0x4000_0000; + let mut exec = map_page_masked::(Arc::new(MockMemory::new()), VA, 0x0300_5000, 0xFFFF_0001); + let phys = exec.debug_translate(VA).phys; + for (rd, value) in [(10, VA), (2, 0)] { + exec.core.write_gpr(1, value); + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_DMTC0 << 21) | (1 << 16) | (rd << 11)), EXEC_COMPLETE); + } + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | FUNCT_TLBP), EXEC_COMPLETE); + assert_eq!(exec.exec((OP_COP0 << 26) | (RS_TLB << 21) | FUNCT_TLBR), EXEC_COMPLETE); + (exec.core.read_cp0(21), exec.core.read_cp0(2), phys) + } + on_big_stack(|| { + // Physical bit 24 is EntryLo bit 18, FrameMask bit 0. + let masked = (((0x0300_5000u64 >> 12) << 6) | (3 << 3) | (1 << 2) | (1 << 1)) & !(1 << 18); + assert_eq!(written::(), (1, masked, 0x0200_5000), "R12000"); + }); } } diff --git a/src/cpu/mips_tlb.rs b/src/cpu/mips_tlb.rs index 166e2bc47..3eaed8e8c 100644 --- a/src/cpu/mips_tlb.rs +++ b/src/cpu/mips_tlb.rs @@ -361,7 +361,7 @@ pub trait Tlb { /// Make a TLB write invalidate every other entry it would match together /// with, as the R10000 and R12000 do (NEC U10278EJ4V0UM, Status register /// TS bit, p.223, and "Avoiding TLB Conflict", p.300): they do not shut - /// down on a multiple match. The R14000 and R16000 are given the same + /// down on a multiple match. The R14000 is given the same /// rule as a model choice, matching QEMU's r10k_invalidate_conflicts(); /// no manual for them was read. Off for the R4400 and R5000, whose /// behaviour on a multiple match is not modelled. diff --git a/src/ip30_machine.rs b/src/ip30_machine.rs index 63b5e589d..32d84895a 100644 --- a/src/ip30_machine.rs +++ b/src/ip30_machine.rs @@ -16,7 +16,8 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use crate::config::{CpuModel, MachineConfig, MachineProfile}; -use crate::cpu::mips_cache_shadow::R10000ShadowCache; +use crate::cpu::mips_cache_v2::MipsCache; +use crate::cpu::mips_cache_shadow::{R10000ShadowCache, R12000ShadowCache, R14000_PRID}; use crate::cpu::smp::World; use crate::cpu::mips_exec::{CpuDevice, MipsCpu, MipsCpuConfig, MipsExecutor}; use crate::cpu::mips_tlb::MipsTlb; @@ -49,9 +50,29 @@ pub const OCTANE_PROM_FILE: &str = "IP30prom.bin"; /// The 195 MHz R10000 of SGI's standard 128 MB Octane configurations (the /// OCTANE Technical Report): Count at half that. pub const OCTANE_COUNT_HZ: u64 = 97_500_000; +/// Count for the 360 MHz R12000 (revision 3.5, 2 MB) that SGI sold in the +/// Octane: half the pipeline clock. +pub const OCTANE_R12000_COUNT_HZ: u64 = 180_000_000; +/// Count for the 600 MHz R14000 (revision 2.4, 2 MB) that SGI sold in the +/// Octane: half the pipeline clock. +pub const OCTANE_R14000_COUNT_HZ: u64 = 300_000_000; + /// R10000 revision 2.7, as an Octane's hinv reports it; the raw PRId is /// inferred from the R10000 manual's encoding. pub const OCTANE_PRID: u32 = 0x0927; + +/// CP0 Count for a part when `[clock] fixed_mhz` is unset: half the clock of +/// one speed that part shipped at in an Octane, so a plain `cpu = "r12000"` +/// or `"r14000"` reports a clock its tuple had. The PROM measures Count +/// against the HEART timer, so `hinv` prints twice this. +fn octane_default_count_hz(cpu: CpuModel) -> u64 { + match cpu { + CpuModel::R12000 => OCTANE_R12000_COUNT_HZ, + CpuModel::R14000 => OCTANE_R14000_COUNT_HZ, + _ => OCTANE_COUNT_HZ, + } +} + /// The Crossbow on the Octane reports revision code 4. const XBOW_REVISION: u32 = 4; /// The Octane2's Crossbow: revision code 5, which IRIX's inventory names @@ -353,7 +374,7 @@ impl OctaneMachine { if has_vpro { kind.label() } else { board.map_or("no graphics", |b| b.label()) } ); - let count_hz = cfg.clock.fixed_mhz.map_or(OCTANE_COUNT_HZ, |mhz| (mhz * 1_000_000.0) as u64); + let count_hz = cfg.clock.fixed_mhz.map_or(octane_default_count_hz(cfg.machine.cpu), |mhz| (mhz * 1_000_000.0) as u64); let flash_lines: Vec<_> = (0..cpu_count) .map(|_| { let bus: Arc = phys.phys.clone(); @@ -365,7 +386,7 @@ impl OctaneMachine { ticks.extend((1..cpu_count).map(|_| Arc::new(AtomicU64::new(0)))); let memory = Arc::new(crate::ip30::memory_map(&cfg.banks[..4])); let cpus: Vec> = (0..cpu_count) - .map(|id| Self::build_cpu(id, cpu_count, memory.clone(), phys.phys.clone(), flash_lines[id as usize].clone(), &timer_manager, count_hz.max(1), ticks[id as usize].clone())) + .map(|id| Self::build_cpu_for(cfg.machine.cpu, id, cpu_count, memory.clone(), phys.phys.clone(), flash_lines[id as usize].clone(), &timer_manager, count_hz.max(1), ticks[id as usize].clone())) .collect(); let cpu = cpus[0].clone(); world.set_slots(cpus.iter().map(|c| c.park_slot()).collect()); @@ -575,8 +596,12 @@ impl OctaneMachine { } } + /// The configured part, as an executor over its cache model. The R10000 + /// takes the Octane's own revision (`OCTANE_PRID`) and the R14000 is the + /// R12000's 2 MB model with its PRId; the R12000 keeps its model's. #[allow(clippy::too_many_arguments)] - fn build_cpu( + fn build_cpu_for( + model: CpuModel, id: u8, cpu_count: u8, memory: Arc, @@ -586,16 +611,46 @@ impl OctaneMachine { count_hz: u64, fasttick: Arc, ) -> Arc { - let cfg = MipsCpuConfig::for_model::(memory); + macro_rules! build { + ($c:ty, $prid:expr) => { + Self::build_cpu::<$c>(id, cpu_count, memory, sysad, cached, tm, count_hz, fasttick, $prid) + }; + } + match model { + CpuModel::R12000 => build!(R12000ShadowCache, None), + CpuModel::R14000 => build!(R12000ShadowCache, Some(R14000_PRID)), + _ => build!(R10000ShadowCache, Some(OCTANE_PRID)), + } + } + + #[allow(clippy::too_many_arguments)] + fn build_cpu( + id: u8, + cpu_count: u8, + memory: Arc, + sysad: Arc, + cached: Arc, + tm: &Arc, + count_hz: u64, + fasttick: Arc, + prid: Option, + ) -> Arc + where + C: crate::cpu::mips_cache_v2::CpuModel + MipsCache + From> + 'static, + MipsCpu: CpuDevice, + { + let cfg = MipsCpuConfig::for_model::(memory); let tlb = MipsTlb::new(cfg.tlb_entries); - let mut exec: MipsExecutor = MipsExecutor::new(sysad, tlb, &cfg); + let mut exec: MipsExecutor = MipsExecutor::new(sysad, tlb, &cfg); // Cached accesses see the PROM's dirty flash lines; see `CachedFlashLines`. - exec.cache = R10000ShadowCache::from(cached as Arc); + exec.cache = C::from(cached as Arc); exec.core.set_timer_manager(tm.clone()); exec.core.set_count_hz(count_hz); exec.core.fasttick_count = fasttick; - exec.core.reset_prid = OCTANE_PRID; - exec.core.cp0_prid = OCTANE_PRID; + if let Some(prid) = prid { + exec.core.reset_prid = prid; + exec.core.cp0_prid = prid; + } // IRIX zeroes Count and arms Compare a few instructions later; see // `MipsCore::count_write_samples`. exec.core.count_write_samples = true; @@ -605,7 +660,7 @@ impl OctaneMachine { exec.phys_mask = (1 << 40) - 1; exec.core.cpu_id = id; exec.core.smp = cpu_count > 1; - exec.batch_hook = Some(Box::new(move |exec: &mut MipsExecutor| { + exec.batch_hook = Some(Box::new(move |exec: &mut MipsExecutor| { LAST_PC[id as usize].store(exec.core.pc, Ordering::Relaxed); })); Arc::new(MipsCpu::new(exec)) @@ -1469,3 +1524,18 @@ mod snapshot_tests { }).unwrap().join().unwrap(); } } + +#[cfg(test)] +mod cpu_clock_tests { + use super::*; + + /// A plain `cpu = ...` reports a clock that part shipped at in an Octane: + /// 195 MHz for the R10000, 360 MHz for the R12000 (revision 3.5) and + /// 600 MHz for the R14000 (revision 2.4). Count runs at half the clock. + #[test] + fn each_octane_part_defaults_to_a_shipped_clock() { + for (cpu, mhz) in [(CpuModel::R10000, 195), (CpuModel::R12000, 360), (CpuModel::R14000, 600)] { + assert_eq!(octane_default_count_hz(cpu) * 2, mhz * 1_000_000, "{cpu:?}"); + } + } +} diff --git a/src/ip32_machine.rs b/src/ip32_machine.rs index a7a42a6d4..fc71c95c2 100644 --- a/src/ip32_machine.rs +++ b/src/ip32_machine.rs @@ -27,7 +27,7 @@ use parking_lot::Mutex; use crate::config::{CpuModel, MachineConfig, MachineProfile}; use crate::cpu::mips_core::CyclesPtr; use crate::cpu::mips_exec::{CpuDevice, MipsCpu, MipsCpuConfig, MipsExecutor}; -use crate::cpu::mips_cache_shadow::{R10000O2ShadowCache, R5000ShadowCache}; +use crate::cpu::mips_cache_shadow::{R10000O2ShadowCache, R12000O2ShadowCache, R5000ShadowCache}; use crate::cpu::mips_cache_v2::MipsCache; use crate::cpu::mips_tlb::MipsTlb; use crate::dev::crime_mem::O2Memory; @@ -157,8 +157,23 @@ pub const O2_PROM_FILE: &str = "ip32prom.rev4.18.bin"; /// CP0 Count when `[clock] fixed_mhz` is unset: half of a 180 MHz CPU. pub const O2_COUNT_MHZ: f64 = 90.0; +/// CP0 Count for the O2's R12000 when `[clock] fixed_mhz` is unset: half of +/// 400 MHz, the speed O2 listings show for revision 3.5. +pub const O2_R12000_COUNT_MHZ: f64 = 200.0; + +/// CP0 Count for a part when `[clock] fixed_mhz` is unset. +fn o2_default_count_mhz(cpu: CpuModel) -> f64 { + match cpu { + CpuModel::R12000 => O2_R12000_COUNT_MHZ, + _ => O2_COUNT_MHZ, + } +} + impl O2Machine { pub fn new(cfg: &MachineConfig) -> Result { + if !matches!(cfg.machine.cpu, CpuModel::R5000 | CpuModel::R10000 | CpuModel::R12000) { + return Err("an O2 has an R5000, R10000 or R12000 ([machine] cpu = \"r5000\", \"r10000\" or \"r12000\")".into()); + } let o2 = &cfg.o2; // `prom`, or the last release's file when `prom` is the shared default // and that file is not there: there is no embedded O2 PROM. @@ -235,14 +250,15 @@ impl O2Machine { let arcs_fpu = o2.arcs_fpu; // `[clock] fixed_mhz` is CP0 Count; the CPU clock the PROM measures // and reports is twice it. - let count_mhz = cfg.clock.fixed_mhz.unwrap_or(O2_COUNT_MHZ); + let count_mhz = cfg.clock.fixed_mhz.unwrap_or(o2_default_count_mhz(cfg.machine.cpu)); let cpu_mhz = (count_mhz * 2.0).round().max(1.0) as u32; let boot = Arc::new(BootState::new()); let memory = Arc::new(crate::ip32::memory_map()); let cpu: Arc = match cfg.machine.cpu { CpuModel::R10000 => Self::build_cpu::(memory.clone(), sysad, &timer_manager, arcs_fpu, cpu_mhz, boot.clone(), bus.ram.clone()), CpuModel::R5000 => Self::build_cpu::(memory.clone(), sysad, &timer_manager, arcs_fpu, cpu_mhz, boot.clone(), bus.ram.clone()), - CpuModel::R4400 => return Err("an O2 has an R5000 or an R10000 ([machine] cpu)".into()), + CpuModel::R12000 => Self::build_cpu::(memory.clone(), sysad, &timer_manager, arcs_fpu, cpu_mhz, boot.clone(), bus.ram.clone()), + CpuModel::R4400 | CpuModel::R14000 => unreachable!("refused at the top of `new`"), }; // ppmem: the CPU's cache and the JIT reach RAM through the memory's @@ -1192,3 +1208,19 @@ fn control_command(bus: &Ip32Bus, cmd: &str, arg: &str, rgba: &mut [u8]) -> Stri } } + +#[cfg(test)] +mod cpu_clock_tests { + use super::*; + + /// A plain `cpu = "r12000"` reports the 400 MHz the revision 3.5 part + /// shipped at; the others keep the 180 MHz default. Count runs at half + /// the clock. + #[test] + fn the_o2_r12000_defaults_to_400_mhz() { + assert_eq!(o2_default_count_mhz(CpuModel::R12000) * 2.0, 400.0); + for cpu in [CpuModel::R5000, CpuModel::R10000] { + assert_eq!(o2_default_count_mhz(cpu) * 2.0, 180.0, "{cpu:?}"); + } + } +} diff --git a/src/machine.rs b/src/machine.rs index 2bc5ac217..a4edf5c15 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -27,7 +27,9 @@ use crate::cpu::mips_tlb::MipsTlb; use crate::cpu::mips_exec::{MipsExecutor, MipsCpu, MipsCpuConfig, MipsCpuDebugAdapter}; use crate::gdb_stub::CpuDebug; use crate::cpu::mips_cache_v2::{MipsCache, R4400Cache, R5000Cache}; -use crate::cpu::mips_cache_shadow::{R10000ShadowCache, R4400ShadowCache, R5000ShadowCache}; +use crate::cpu::mips_cache_shadow::{ + R10000ShadowCache, R12000ShadowCache, R14000_PRID, R4400ShadowCache, R5000ShadowCache, +}; use crate::dev::hpc3::Hpc3; use crate::dev::ioc::{Ioc, GioSlot, GIO_SLOT_MAP, profile_idx}; use crate::monitor::Monitor; @@ -354,6 +356,8 @@ impl Machine { crate::config::CpuModel::R4400 => ::L2_SIZE > 0, crate::config::CpuModel::R5000 => ::L2_SIZE > 0, crate::config::CpuModel::R10000 => ::L2_SIZE > 0, + crate::config::CpuModel::R12000 => ::L2_SIZE > 0, + crate::config::CpuModel::R14000 => ::L2_SIZE > 0, }; if !model_has_l2 { eeprom_mc.lock().set_cachsz(0); @@ -741,12 +745,17 @@ impl Machine { // arm below monomorphises its own CPU — no per-model branch on the hot path. let sysad: Arc = phys.clone(); let memory = Arc::new(crate::ip22_bus::memory_map(cfg.machine.profile.ip28())); - macro_rules! build_cpu { ($cache:ty) => {{ + macro_rules! build_cpu { ($cache:ty $(, $prid:expr)?) => {{ let cfg = MipsCpuConfig::for_model::<$cache>(memory.clone()); let tlb = MipsTlb::new(cfg.tlb_entries); let mut executor: MipsExecutor = MipsExecutor::new(sysad.clone(), tlb, &cfg); // The MC decodes 32 physical address bits; see `MipsExecutor::phys_mask`. executor.phys_mask = u32::MAX as u64; + // A part that shares another's model differs in PRId. + $( + executor.core.reset_prid = $prid; + executor.core.cp0_prid = $prid; + )? // Load default symbol maps if they exist { @@ -800,6 +809,8 @@ impl Machine { // tag and data arrays that exist only to answer CACHE ops and the // PROM's diagnostics. See mips_cache_shadow.rs. crate::config::CpuModel::R10000 => build_cpu!(R10000ShadowCache), + crate::config::CpuModel::R12000 => build_cpu!(R12000ShadowCache), + crate::config::CpuModel::R14000 => build_cpu!(R12000ShadowCache, R14000_PRID), }; // The developer status bar shows the CPU's Count rate.