interconnect.ha (6656B)
1 use bios; 2 use fmt; 3 use util; 4 use ram; 5 6 export type Interconnect = struct { 7 bios: bios::BIOS, 8 ram: ram::ram, 9 }; 10 11 export fn new(bios: bios::BIOS, ram: ram::ram) Interconnect = { 12 return Interconnect { 13 bios = bios, 14 ram = ram 15 }; 16 }; 17 18 export fn store32(inter: Interconnect, addr: u32, val: u32) void = { 19 20 if (addr % 4 != 0) 21 fmt::fatalf("Unaligned load32 address: {:.08X}", addr); 22 23 let abs_addr = util::mask_region(addr); 24 25 match(util::contains(util::MEMCONTROL_START: u32, util::MEMCONTROL_SIZE: u32, abs_addr)) { 26 case let off: u32 => 27 switch (off) { 28 case 0 => 29 if (val != 0x1f000000) 30 fmt::fatalf("Bad expansion 1 base address: {:.08X}", val); 31 case 4 => 32 if (val != 0x1f802000) 33 fmt::fatalf("Bad expansion 2 base address: {:.08X}", val); 34 case => 35 fmt::println("Unhandled write to MEMCONTROL Register")!; 36 37 }; 38 return; 39 case void => yield; 40 }; 41 42 match(util::contains(util::RAM_SIZE_START: u32, util::RAM_SIZE_SIZE: u32, abs_addr)) { 43 case let off: u32 => fmt::println("Unhandled write to RAM SIZE register")!; return; 44 case void => yield; 45 }; 46 47 match(util::contains(util::CACHE_CONTROL_START: u32, util::CACHE_CONTROL_SIZE: u32, abs_addr)) { 48 case let off: u32 => fmt::println("Unhandled write to CACHE CONTROL register")!; return; 49 case void => yield; 50 }; 51 52 match(util::contains(util::RAM_START: u32, util::RAM_SIZE: u32, abs_addr)) { 53 case let off: u32 => ram::store32(inter.ram, off, val); return; 54 case void => yield; 55 }; 56 57 match(util::contains(util::IRQ_CONTROL_START: u32, util::IRQ_CONTROL_SIZE: u32, abs_addr)) { 58 case let off: u32 => fmt::printfln("IRQ control: {:.08X} <- {:X}", off, val)!; return; 59 case void => yield; 60 }; 61 62 match(util::contains(util::DMA_START: u32, util::DMA_SIZE: u32, abs_addr)) { 63 case let off: u32 => fmt::printfln("DMA write: {:.08X} <- {:X}", abs_addr, val)!; return; 64 case void => yield; 65 }; 66 67 match(util::contains(util::GPU_START: u32, util::GPU_SIZE: u32, abs_addr)) { 68 case let off: u32 => fmt::printfln("GPU write: {:.08X} <- {:X}", off, val)!; return; 69 case void => yield; 70 }; 71 72 match(util::contains(util::TIMERS_START: u32, util::TIMERS_SIZE: u32, abs_addr)) { 73 case let off: u32 => fmt::printfln("Timer register write: {:.08X} <- {:X}", off, val)!; return; 74 case void => yield; 75 }; 76 77 fmt::fatalf("Unhandled store32 into address {:.08X}", abs_addr); 78 }; 79 80 export fn store16(inter: Interconnect, addr: u32, val: u16) void = { 81 82 if (addr % 2 != 0) 83 fmt::fatalf("Unaligned store16 address: {:.08X}", addr); 84 85 let abs_addr = util::mask_region(addr); 86 87 match(util::contains(util::SPU_START: u32, util::SPU_SIZE: u32, abs_addr)) { 88 case let off: u32 => 89 if (util::DEBUG) fmt::printfln("Unhandled write to SPU register {:X}", off)!; return; 90 case void => yield; 91 }; 92 93 match(util::contains(util::TIMERS_START: u32, util::TIMERS_SIZE: u32, abs_addr)) { 94 case let off: u32 => 95 if (util::DEBUG) fmt::printfln("Unhandled write to Timer register {:X}", off)!; return; 96 case void => yield; 97 }; 98 99 match(util::contains(util::RAM_START: u32, util::RAM_SIZE: u32, abs_addr)) { 100 case let off: u32 => ram::store16(inter.ram, off, val); return; 101 case void => yield; 102 }; 103 104 match(util::contains(util::IRQ_CONTROL_START: u32, util::IRQ_CONTROL_SIZE: u32, abs_addr)) { 105 case let off: u32 => 106 if (util::DEBUG) fmt::printfln("IRQ control write: {:X} <- {:.04X}", off, val)!; 107 return; 108 case void => yield; 109 }; 110 111 fmt::fatalf("Unhandled store16 into address {:.08X}", abs_addr); 112 }; 113 114 export fn store8(inter: Interconnect, addr: u32, val: u8) void = { 115 116 let abs_addr = util::mask_region(addr); 117 118 match(util::contains(util::EXPANSION_2_START: u32, util::EXPANSION_2_SIZE: u32, abs_addr)) { 119 case let off: u32 => 120 fmt::printfln("Unhandled write to Expansion 2 register {:X}", off)!; return; 121 case void => yield; 122 }; 123 124 match(util::contains(util::RAM_START: u32, util::RAM_SIZE: u32, abs_addr)) { 125 case let off: u32 => 126 return ram::store8(inter.ram, off, val); 127 case void => yield; 128 }; 129 130 fmt::fatalf("Unhandled store8 into address {:.08X}", addr); 131 }; 132 133 export fn load32(inter: Interconnect, addr: u32) u32 = { 134 if (addr % 4 != 0) 135 fmt::fatalf("Unaligned store32 into address {:.08X}", addr); 136 137 let abs_addr = util::mask_region(addr); 138 139 match(util::contains(util::BIOS_START: u32, util::BIOS_SIZE: u32, abs_addr)) { 140 case let off: u32 => 141 return bios::load32(inter.bios, off); 142 case void => 143 yield; 144 }; 145 146 match(util::contains(util::RAM_START: u32, util::RAM_SIZE: u32, abs_addr)) { 147 case let off: u32 => 148 return ram::load32(inter.ram, off); 149 case void => 150 yield; 151 }; 152 153 match(util::contains(util::IRQ_CONTROL_START: u32, util::IRQ_CONTROL_SIZE: u32, abs_addr)) { 154 case let off: u32 => 155 fmt::printfln("IRQ control read {:X}", off)!; return 0; 156 case void => 157 yield; 158 }; 159 160 match(util::contains(util::DMA_START: u32, util::DMA_SIZE: u32, abs_addr)) { 161 case let off: u32 => 162 fmt::printfln("DMA read {:X}", abs_addr)!; return 0; 163 case void => 164 yield; 165 }; 166 167 match(util::contains(util::GPU_START: u32, util::GPU_SIZE: u32, abs_addr)) { 168 case let off: u32 => 169 fmt::printfln("GPU read {:X}", off)!; 170 let bit: u32 = switch(off) { 171 case 4 => yield 0x10000000; 172 case => yield 0; 173 }; 174 175 return bit; 176 case void => 177 yield; 178 }; 179 180 fmt::fatalf("Unhandled fetch32 at address {:.08X}", abs_addr); 181 }; 182 183 export fn load16(inter: Interconnect, addr: u32) u16 = { 184 let abs_addr = util::mask_region(addr); 185 186 match(util::contains(util::SPU_START: u32, util::SPU_SIZE: u32, abs_addr)) { 187 case let off: u32 => 188 if (util::DEBUG) fmt::printfln("Unhandled read from SPU register: {:.08X}", abs_addr)!; return 0; 189 case void => 190 yield; 191 }; 192 193 match(util::contains(util::RAM_START: u32, util::RAM_SIZE: u32, abs_addr)) { 194 case let off: u32 => 195 return ram::load16(inter.ram, off); 196 case void => 197 yield; 198 }; 199 200 match(util::contains(util::IRQ_CONTROL_START: u32, util::IRQ_CONTROL_SIZE: u32, abs_addr)) { 201 case let off: u32 => 202 fmt::printfln("IRQ control read: {:.08X}", off)!; return 0; 203 case void => 204 yield; 205 }; 206 207 fmt::fatalf("Unhandled fetch16 at address {:.08X}", abs_addr); 208 }; 209 210 export fn load8(inter: Interconnect, addr: u32) u8 = { 211 let abs_addr = util::mask_region(addr); 212 213 match(util::contains(util::BIOS_START: u32, util::BIOS_SIZE: u32, abs_addr)) { 214 case let off: u32 => 215 return bios::load8(inter.bios, off); 216 case void => 217 yield; 218 }; 219 220 match(util::contains(util::RAM_START: u32, util::RAM_SIZE: u32, abs_addr)) { 221 case let off: u32 => 222 return ram::load8(inter.ram, off); 223 case void => 224 yield; 225 }; 226 227 match(util::contains(util::EXPANSION_1_START: u32, util::EXPANSION_1_SIZE: u32, abs_addr)) { 228 case let off: u32 => 229 return 0xff; 230 case void => 231 yield; 232 }; 233 234 fmt::fatalf("Unhandled fetch8 at address {:.08X}", abs_addr); 235 };