├── .gitattributes ├── .gitignore ├── ChocolateARM.sln ├── ChocolateARM ├── ARM11 │ ├── ARM │ │ ├── AddressingModes │ │ │ ├── DataProcessing.cs │ │ │ └── LoadAndStore.cs │ │ └── Instructions │ │ │ ├── ARM │ │ │ ├── Arithmetic │ │ │ │ ├── Addition.cs │ │ │ │ ├── Multiplication.cs │ │ │ │ ├── Saturation.cs │ │ │ │ └── Subtraction.cs │ │ │ ├── Branch.cs │ │ │ ├── Compare.cs │ │ │ ├── Coprocessor.cs │ │ │ ├── Exception.cs │ │ │ ├── LoadAndStore.cs │ │ │ ├── LoadAndStore │ │ │ │ ├── Load.cs │ │ │ │ └── Store.cs │ │ │ ├── Logical.cs │ │ │ └── Move.cs │ │ │ └── Thumb │ │ │ ├── Arithmetic.cs │ │ │ ├── Branch.cs │ │ │ ├── Compare.cs │ │ │ ├── Exception.cs │ │ │ ├── LoadAndStore.cs │ │ │ ├── Logical.cs │ │ │ └── Move.cs │ ├── ARMCore.cs │ ├── Bus.cs │ ├── Condition.cs │ ├── Coprocessor15.cs │ ├── Registers.cs │ └── Utils.cs ├── App.config ├── ChocolateARM.csproj ├── FrmMain.Designer.cs ├── FrmMain.cs ├── FrmMain.resx ├── FrmUARTOutput.Designer.cs ├── FrmUARTOutput.cs ├── FrmUARTOutput.resx ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── RPi │ ├── IO32.cs │ ├── Memory.cs │ ├── Peripherals │ ├── RPiDMA.cs │ ├── RPiMiniUART.cs │ ├── RPiTimer.cs │ └── RPiUART.cs │ ├── RPiCore.cs │ └── VideoCore.cs └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 19 | !packages/*/build/ 20 | 21 | # MSTest test Results 22 | [Tt]est[Rr]esult*/ 23 | [Bb]uild[Ll]og.* 24 | 25 | *_i.c 26 | *_p.c 27 | *.ilk 28 | *.meta 29 | *.obj 30 | *.pch 31 | *.pdb 32 | *.pgc 33 | *.pgd 34 | *.rsp 35 | *.sbr 36 | *.tlb 37 | *.tli 38 | *.tlh 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | *.vspscc 43 | *.vssscc 44 | .builds 45 | *.pidb 46 | *.log 47 | *.scc 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | *.cachefile 56 | 57 | # Visual Studio profiler 58 | *.psess 59 | *.vsp 60 | *.vspx 61 | 62 | # Guidance Automation Toolkit 63 | *.gpState 64 | 65 | # ReSharper is a .NET coding add-in 66 | _ReSharper*/ 67 | *.[Rr]e[Ss]harper 68 | 69 | # TeamCity is a build add-in 70 | _TeamCity* 71 | 72 | # DotCover is a Code Coverage Tool 73 | *.dotCover 74 | 75 | # NCrunch 76 | *.ncrunch* 77 | .*crunch*.local.xml 78 | 79 | # Installshield output folder 80 | [Ee]xpress/ 81 | 82 | # DocProject is a documentation generator add-in 83 | DocProject/buildhelp/ 84 | DocProject/Help/*.HxT 85 | DocProject/Help/*.HxC 86 | DocProject/Help/*.hhc 87 | DocProject/Help/*.hhk 88 | DocProject/Help/*.hhp 89 | DocProject/Help/Html2 90 | DocProject/Help/html 91 | 92 | # Click-Once directory 93 | publish/ 94 | 95 | # Publish Web Output 96 | *.Publish.xml 97 | 98 | # NuGet Packages Directory 99 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 100 | #packages/ 101 | 102 | # Windows Azure Build Output 103 | csx 104 | *.build.csdef 105 | 106 | # Windows Store app package directory 107 | AppPackages/ 108 | 109 | # Others 110 | sql/ 111 | *.Cache 112 | ClientBin/ 113 | [Ss]tyle[Cc]op.* 114 | ~$* 115 | *~ 116 | *.dbmdl 117 | *.[Pp]ublish.xml 118 | *.pfx 119 | *.publishsettings 120 | 121 | # RIA/Silverlight projects 122 | Generated_Code/ 123 | 124 | # Backup & report files from converting an old project file to a newer 125 | # Visual Studio version. Backup files are not needed, because we have git ;-) 126 | _UpgradeReport_Files/ 127 | Backup*/ 128 | UpgradeLog*.XML 129 | UpgradeLog*.htm 130 | 131 | # SQL Server files 132 | App_Data/*.mdf 133 | App_Data/*.ldf 134 | 135 | 136 | #LightSwitch generated files 137 | GeneratedArtifacts/ 138 | _Pvt_Extensions/ 139 | ModelManifest.xml 140 | 141 | # ========================= 142 | # Windows detritus 143 | # ========================= 144 | 145 | # Windows image file caches 146 | Thumbs.db 147 | ehthumbs.db 148 | 149 | # Folder config file 150 | Desktop.ini 151 | 152 | # Recycle Bin used on file shares 153 | $RECYCLE.BIN/ 154 | 155 | # Mac desktop service store files 156 | .DS_Store 157 | -------------------------------------------------------------------------------- /ChocolateARM.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChocolateARM", "ChocolateARM\ChocolateARM.csproj", "{47232F73-385B-43D6-8751-10B289DAEBE1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {47232F73-385B-43D6-8751-10B289DAEBE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {47232F73-385B-43D6-8751-10B289DAEBE1}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {47232F73-385B-43D6-8751-10B289DAEBE1}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {47232F73-385B-43D6-8751-10B289DAEBE1}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/AddressingModes/DataProcessing.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Decodes the Operand value from the Shifter Operand. 7 | /// 8 | /// True if the Carry flag should be updated with the shifting operations, false otherwise 9 | /// The decoded Operand value 10 | private uint ARM_GetShifterOperand(bool S) 11 | { 12 | bool I = IsOpcodeBitSet(25); 13 | uint ShifterOperand = Opcode & 0xfff; 14 | 15 | if (I) //Immediate 16 | { 17 | int Rotate = (int)((ShifterOperand >> 8) << 1); 18 | uint Operand = ROR(ShifterOperand & 0xff, Rotate); 19 | if (S && Rotate > 0) Registers.SetFlag(ARMFlag.Carry, (Operand & 0x80000000) != 0); 20 | return Operand; 21 | } 22 | else //Register 23 | { 24 | uint Operand = 0; 25 | bool Carry = false; 26 | int Rm = (int)(ShifterOperand & 0xf); 27 | uint Shifter = (Opcode >> 5) & 3; 28 | 29 | int Shift; 30 | bool Register = IsOpcodeBitSet(4); 31 | if (Register) 32 | { 33 | int Rs = (int)((ShifterOperand >> 8) & 0xf); 34 | Shift = (int)(Registers[Rs] & 0xff); 35 | } 36 | else 37 | { 38 | Shift = (int)((ShifterOperand >> 7) & 0x1f); 39 | if (Shift == 0 && (Shifter == 1 || Shifter == 2)) Shift = 32; 40 | } 41 | 42 | if (Shift > 0 && Shift <= 32) 43 | { 44 | switch (Shifter) 45 | { 46 | case 0: //LSL 47 | Operand = Shift < 32 ? Registers[Rm] << Shift : 0; 48 | Carry = (Registers[Rm] & (1 << (32 - Shift))) != 0; 49 | break; 50 | 51 | case 1: //LSR 52 | Operand = Shift < 32 ? Registers[Rm] >> Shift : 0; 53 | Carry = (Registers[Rm] & (1 << (Shift - 1))) != 0; 54 | break; 55 | 56 | case 2: //ASR 57 | int RmValue = (int)Registers[Rm]; 58 | Operand = (uint)((long)RmValue >> Shift); 59 | Carry = (RmValue & (1 << (Shift - 1))) != 0; 60 | break; 61 | 62 | case 3: //ROR 63 | if (Register) Shift &= 0x1f; 64 | Operand = ROR(Registers[Rm], Shift); 65 | if (Shift > 0) 66 | Carry = (Registers[Rm] & (1 << (Shift - 1))) != 0; 67 | else 68 | Carry = (Registers[Rm] & 0x80000000) != 0; 69 | break; 70 | } 71 | } 72 | else 73 | { 74 | if (Shift == 0) 75 | { 76 | Operand = Registers[Rm]; 77 | Carry = Registers.IsFlagSet(ARMFlag.Carry); 78 | 79 | if (!Register && Shifter == 3) //RRX 80 | { 81 | Operand = (Operand >> 1) | (Carry ? 0x80000000 : 0); 82 | Carry = (Registers[Rm] & 1) != 0; 83 | } 84 | } 85 | else if (Shifter > 1) 86 | { 87 | Carry = (Registers[Rm] & 0x80000000) != 0; 88 | Operand = Carry ? 0xffffffff : 0; 89 | } 90 | } 91 | 92 | if (S) Registers.SetFlag(ARMFlag.Carry, Carry); 93 | return Operand; 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/AddressingModes/LoadAndStore.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Gets the Address used for the general Load and Store instructions. 7 | /// 8 | /// The Base Address to Load or Store 9 | private uint ARM_GetLoadAndStoreAddress() 10 | { 11 | int Rn = (int)((Opcode >> 16) & 0xf); 12 | bool W = IsOpcodeBitSet(21); 13 | bool U = IsOpcodeBitSet(23); 14 | bool P = IsOpcodeBitSet(24); 15 | bool I = IsOpcodeBitSet(25); 16 | 17 | ARMMode OldMode = Registers.Mode; 18 | if (!P && W) Registers.Mode = ARMMode.User; 19 | uint Offset = 0; 20 | if (I) //Register 21 | { 22 | int Rm = (int)(Opcode & 0xf); 23 | uint Shift = (Opcode >> 5) & 3; 24 | int ShiftImmediate = (int)((Opcode >> 7) & 0x1f); 25 | 26 | switch (Shift) 27 | { 28 | case 0: Offset = Registers[Rm] << ShiftImmediate; break; //LSL 29 | case 1: Offset = ShiftImmediate != 0 ? Registers[Rm] >> ShiftImmediate : 0; break; //LSR 30 | 31 | case 2: //ASR 32 | if (ShiftImmediate == 0) 33 | Offset = (Registers[Rm] & 0x80000000) != 0 ? 0xffffffff : 0; 34 | else 35 | Offset = Registers[Rm] >> ShiftImmediate; 36 | break; 37 | 38 | case 3: //ROR 39 | if (ShiftImmediate == 0) 40 | Offset = (Registers[Rm] >> 1) | (Registers.IsFlagSet(ARMFlag.Carry) ? 0x80000000 : 0); 41 | else 42 | Offset = ROR(Registers[Rm], ShiftImmediate); 43 | break; 44 | } 45 | } 46 | else //Immediate 47 | Offset = Opcode & 0xfff; 48 | 49 | uint Address = 0; 50 | if (P) 51 | { 52 | if (W) //Pre-Indexed 53 | { 54 | if (U) 55 | Registers[Rn] += Offset; 56 | else 57 | Registers[Rn] -= Offset; 58 | 59 | Address = Registers[Rn]; 60 | } 61 | else //Offset 62 | Address = U ? Registers[Rn] + Offset : Registers[Rn] - Offset; 63 | } 64 | else 65 | { 66 | if (!W) //Post-Indexed 67 | { 68 | Address = Registers[Rn]; 69 | 70 | if (U) 71 | Registers[Rn] += Offset; 72 | else 73 | Registers[Rn] -= Offset; 74 | } 75 | } 76 | 77 | Registers.Mode = OldMode; 78 | return Address; 79 | } 80 | 81 | /// 82 | /// Gets the Address used to Load or Store on the Coprocessor-related instructions. 83 | /// 84 | /// The Base Address to Load or Store 85 | private uint ARM_GetLoadAndStoreCPAddress() 86 | { 87 | uint Offset = (Opcode & 0xff) << 2; 88 | int Rn = (int)((Opcode >> 16) & 0xf); 89 | bool W = IsOpcodeBitSet(21); 90 | bool U = IsOpcodeBitSet(23); 91 | bool P = IsOpcodeBitSet(24); 92 | 93 | uint Address; 94 | if (P) 95 | { 96 | if (W) //Pre-Indexed 97 | { 98 | if (U) 99 | Registers[Rn] += Offset; 100 | else 101 | Registers[Rn] -= Offset; 102 | 103 | Address = Registers[Rn]; 104 | } 105 | else //Offset 106 | Address = U ? Registers[Rn] + Offset : Registers[Rn] - Offset; 107 | } 108 | else 109 | { 110 | if (W) //Post-Indexed 111 | { 112 | Address = Registers[Rn]; 113 | 114 | if (U) 115 | Registers[Rn] += Offset; 116 | else 117 | Registers[Rn] -= Offset; 118 | } 119 | else //Unindexed 120 | Address = Registers[Rn]; 121 | } 122 | 123 | return Address; 124 | } 125 | 126 | /// 127 | /// Gets the Address used on Load or Store instruction that uses values bigger or smaller than 32-bits. 128 | /// 129 | /// The Base Address to Load or Store 130 | private uint ARM_GetLoadAndStoreNonWordAddress() 131 | { 132 | int Rn = (int)((Opcode >> 16) & 0xf); 133 | bool W = IsOpcodeBitSet(21); 134 | bool I = IsOpcodeBitSet(22); 135 | bool U = IsOpcodeBitSet(23); 136 | bool P = IsOpcodeBitSet(24); 137 | 138 | uint Offset; 139 | if (I) //Immediate 140 | Offset = (Opcode & 0xf) | ((Opcode >> 4) & 0xf0); 141 | else //Register 142 | Offset = Registers[(int)(Opcode & 0xf)]; 143 | 144 | uint Address = 0; 145 | if (P) 146 | { 147 | if (W) //Pre-Indexed 148 | { 149 | if (U) 150 | Registers[Rn] += Offset; 151 | else 152 | Registers[Rn] -= Offset; 153 | 154 | Address = Registers[Rn]; 155 | } 156 | else //Offset 157 | Address = U ? Registers[Rn] + Offset : Registers[Rn] - Offset; 158 | } 159 | else 160 | { 161 | if (!W) //Post-Indexed 162 | { 163 | Address = Registers[Rn]; 164 | 165 | if (U) 166 | Registers[Rn] += Offset; 167 | else 168 | Registers[Rn] -= Offset; 169 | } 170 | } 171 | 172 | return Address; 173 | } 174 | 175 | /// 176 | /// Gets the Address used on Load or Store Multiple instructions. 177 | /// 178 | /// The Base Address to Load or Store 179 | private uint ARM_GetLoadAndStoreMultipleAddress() 180 | { 181 | ushort RegisterList = (ushort)(Opcode & 0xffff); 182 | int Rn = (int)((Opcode >> 16) & 0xf); 183 | bool W = IsOpcodeBitSet(21); 184 | bool U = IsOpcodeBitSet(23); 185 | bool P = IsOpcodeBitSet(24); 186 | 187 | uint Count = 0; 188 | for (int Index = 0; Index < 16; Index++) 189 | { 190 | if ((RegisterList & (1 << Index)) != 0) Count += 4; 191 | } 192 | 193 | uint Address; 194 | if (U) 195 | Address = Registers[Rn] + (uint)(P ? 4 : 0); 196 | else 197 | Address = Registers[Rn] - Count + (uint)(P ? 0 : 4); 198 | 199 | if (W) 200 | { 201 | if (U) 202 | Registers[Rn] += Count; 203 | else 204 | Registers[Rn] -= Count; 205 | } 206 | 207 | return Address; 208 | } 209 | 210 | /// 211 | /// Gets the Address used by the SRS (Store Return State) instruction. 212 | /// 213 | /// The Base Address to Store 214 | private uint ARM_GetSRSAddress() 215 | { 216 | int Rn = (int)((Opcode >> 16) & 0xf); 217 | bool W = IsOpcodeBitSet(21); 218 | bool U = IsOpcodeBitSet(23); 219 | bool P = IsOpcodeBitSet(24); 220 | 221 | uint Address; 222 | if (U) 223 | Address = Registers[Rn] + (uint)(P ? 4 : 0); 224 | else 225 | Address = Registers[Rn] - 8 + (uint)(P ? 0 : 4); 226 | 227 | if (W) 228 | { 229 | if (U) 230 | Registers[Rn] += 8; 231 | else 232 | Registers[Rn] -= 8; 233 | } 234 | 235 | return Address; 236 | } 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/Arithmetic/Saturation.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /* 6 | * Instructions 7 | */ 8 | 9 | //Signed 10 | 11 | /// 12 | /// Signed Saturate. 13 | /// 14 | private void ARM_SSAT() 15 | { 16 | int Rm = (int)(Opcode & 0xf); 17 | bool Shift = IsOpcodeBitSet(6); 18 | int ShiftImmediate = (int)((Opcode >> 7) & 0x1f); 19 | int Rd = (int)((Opcode >> 12) & 0xf); 20 | int SaturateImmediate = (int)(((Opcode >> 16) & 0x1f) + 1); 21 | 22 | int RmValue = (int)Registers[Rm]; 23 | if (Shift) 24 | RmValue >>= ShiftImmediate == 0 ? 32 : ShiftImmediate; 25 | else 26 | RmValue <<= ShiftImmediate; 27 | 28 | Registers[Rd] = SignedSaturate(RmValue, SaturateImmediate); 29 | } 30 | 31 | /// 32 | /// Signed Saturate 16-bits. 33 | /// 34 | private void ARM_SSAT16() 35 | { 36 | int Rm = (int)(Opcode & 0xf); 37 | int Rd = (int)((Opcode >> 12) & 0xf); 38 | int SaturateImmediate = (int)(((Opcode >> 16) & 0xf) + 1); 39 | 40 | Registers[Rd] = SignedSaturate((int)(Registers[Rm] & 0xffff), SaturateImmediate); 41 | Registers[Rd] |= SignedSaturate((int)(Registers[Rm] >> 16), SaturateImmediate) << 16; 42 | } 43 | 44 | //Unsigned 45 | 46 | /// 47 | /// Unsigned Saturate. 48 | /// 49 | private void ARM_USAT() 50 | { 51 | int Rm = (int)(Opcode & 0xf); 52 | bool Shift = IsOpcodeBitSet(6); 53 | int ShiftImmediate = (int)((Opcode >> 7) & 0x1f); 54 | int Rd = (int)((Opcode >> 12) & 0xf); 55 | int SaturateImmediate = (int)(((Opcode >> 16) & 0x1f) + 1); 56 | 57 | int RmValue = (int)Registers[Rm]; 58 | if (Shift) 59 | RmValue >>= ShiftImmediate == 0 ? 32 : ShiftImmediate; 60 | else 61 | RmValue <<= ShiftImmediate; 62 | 63 | Registers[Rd] = UnsignedSaturate(RmValue, SaturateImmediate); 64 | } 65 | 66 | /// 67 | /// Unsigned Saturate 16-bits. 68 | /// 69 | private void ARM_USAT16() 70 | { 71 | int Rm = (int)(Opcode & 0xf); 72 | int Rd = (int)((Opcode >> 12) & 0xf); 73 | int SaturateImmediate = (int)(((Opcode >> 16) & 0xf) + 1); 74 | 75 | Registers[Rd] = UnsignedSaturate((int)(Registers[Rm] & 0xffff), SaturateImmediate); 76 | Registers[Rd] |= UnsignedSaturate((int)(Registers[Rm] >> 16), SaturateImmediate) << 16; 77 | } 78 | 79 | /* 80 | * Utils 81 | */ 82 | 83 | /// 84 | /// Saturates a signed 32-bits Value into a given range of Bits. 85 | /// 86 | /// The value that should be saturated 87 | /// The bit-range to saturate the value into 88 | /// The saturated value 89 | private uint SignedSaturate(int Value, int Bits) 90 | { 91 | uint Mask = (uint)((1 << Bits) - 1); 92 | int High = Value >> Bits; 93 | if (High > 0 || High < -1) 94 | { 95 | Registers.SetFlag(ARMFlag.Saturation, true); 96 | return High > 0 ? Mask : ~Mask; 97 | } 98 | else 99 | return (uint)Value; 100 | } 101 | 102 | /// 103 | /// Saturates a unsigned 32-bits Value into a given range of Bits. 104 | /// 105 | /// The value that should be saturated 106 | /// The bit-range to saturate the value into 107 | /// The saturated value 108 | private uint UnsignedSaturate(int Value, int Bits) 109 | { 110 | uint Mask = (uint)((1 << Bits) - 1); 111 | if (Value > Mask || (Value & 0x80000000) != 0) 112 | { 113 | Registers.SetFlag(ARMFlag.Saturation, true); 114 | return Value > Mask ? Mask : 0; 115 | } 116 | else 117 | return (uint)Value; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/Branch.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Branch. 7 | /// 8 | private void ARM_B() 9 | { 10 | int Value = SignExtend24(Opcode & 0xffffff); 11 | bool L = IsOpcodeBitSet(24); 12 | 13 | if (L) Registers[14] = Registers[15] - 4; 14 | Registers[15] = (uint)(Registers[15] + (Value << 2)); 15 | } 16 | 17 | /// 18 | /// Branch with Link and Exchange (1). 19 | /// 20 | private void ARM_BLX() 21 | { 22 | int Value = SignExtend24(Opcode & 0xffffff); 23 | uint H = (Opcode >> 24) & 1; 24 | 25 | Registers[15] = (uint)(Registers[15] + (Value << 2) + (H << 1)); 26 | } 27 | 28 | /// 29 | /// Branch with Link and Exchange (2). 30 | /// 31 | private void ARM_BLX_2() 32 | { 33 | int Rm = (int)(Opcode & 0xf); 34 | 35 | Registers[14] = Registers[15] - 4; 36 | Registers[15] = Registers[Rm] & 0xfffffffe; 37 | Registers.SetFlag(ARMFlag.Thumb, (Registers[Rm] & 1) != 0); 38 | } 39 | 40 | /// 41 | /// Branch and Exchange. 42 | /// 43 | private void ARM_BX() 44 | { 45 | int Rm = (int)(Opcode & 0xf); 46 | 47 | Registers[15] = Registers[Rm] & 0xfffffffe; 48 | Registers.SetFlag(ARMFlag.Thumb, (Registers[Rm] & 1) != 0); 49 | } 50 | 51 | /// 52 | /// Branch and Exchange to Jazelle state. 53 | /// 54 | private void ARM_BXJ() 55 | { 56 | //Note: This processor doesn't support Jazelle, act as BX. 57 | ARM_BX(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/Compare.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Compare Negative. 7 | /// 8 | private void ARM_CMN() 9 | { 10 | int Rn = (int)((Opcode >> 16) & 0xf); 11 | uint ShifterOperand = ARM_GetShifterOperand(true); 12 | 13 | Add(Registers[Rn], ShifterOperand, false, true); 14 | } 15 | 16 | /// 17 | /// Compare. 18 | /// 19 | private void ARM_CMP() 20 | { 21 | int Rn = (int)((Opcode >> 16) & 0xf); 22 | uint ShifterOperand = ARM_GetShifterOperand(true); 23 | 24 | Subtract(Registers[Rn], ShifterOperand, false, true); 25 | } 26 | 27 | /// 28 | /// Test Equivalence. 29 | /// 30 | private void ARM_TEQ() 31 | { 32 | int Rn = (int)((Opcode >> 16) & 0xf); 33 | uint ShifterOperand = ARM_GetShifterOperand(true); 34 | 35 | SetZNFlags(Registers[Rn] ^ ShifterOperand); 36 | } 37 | 38 | /// 39 | /// Test. 40 | /// 41 | private void ARM_TST() 42 | { 43 | int Rn = (int)((Opcode >> 16) & 0xf); 44 | uint ShifterOperand = ARM_GetShifterOperand(true); 45 | 46 | SetZNFlags(Registers[Rn] & ShifterOperand); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/Coprocessor.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /* 6 | * Note: Most of those instructions are just stubs, since coprocessors aren't implemented, 7 | * except for a few stuff of CP15. It have just the enough to make basic stuff work. 8 | */ 9 | 10 | /// 11 | /// Coprocessor Data Processing. 12 | /// 13 | private void ARM_CDP() 14 | { 15 | int CRm = (int)(Opcode & 0xf); 16 | uint Opcode2 = (Opcode >> 5) & 7; 17 | uint CoprocessorIndex = (Opcode >> 8) & 0xf; 18 | int CRd = (int)((Opcode >> 12) & 0xf); 19 | int CRn = (int)((Opcode >> 16) & 0xf); 20 | uint Opcode1 = (Opcode >> 20) & 0xf; 21 | } 22 | 23 | /// 24 | /// Load Coprocessor. 25 | /// 26 | private void ARM_LDC() 27 | { 28 | uint CoprocessorIndex = (Opcode >> 8) & 0xf; 29 | int CRd = (int)((Opcode >> 12) & 0xf); 30 | bool N = (Opcode & 0x400000) != 0; 31 | uint Address = ARM_GetLoadAndStoreCPAddress(); 32 | } 33 | 34 | /// 35 | /// Move to Coprocessor from Register. 36 | /// 37 | private void ARM_MCR() 38 | { 39 | int CRm = (int)(Opcode & 0xf); 40 | uint Opcode2 = (Opcode >> 5) & 7; 41 | uint CoprocessorIndex = (Opcode >> 8) & 0xf; 42 | int Rd = (int)((Opcode >> 12) & 0xf); 43 | int CRn = (int)((Opcode >> 16) & 0xf); 44 | uint Opcode1 = (Opcode >> 21) & 7; 45 | 46 | if (CoprocessorIndex == 15) CP15.Write(CRn, Opcode1, CRm, Opcode2, Registers[Rd]); 47 | } 48 | 49 | /// 50 | /// Move to Coprocessor from two Registers. 51 | /// 52 | private void ARM_MCRR() 53 | { 54 | int CRm = (int)(Opcode & 0xf); 55 | uint CoprocessorOpcode = (Opcode >> 4) & 0xf; 56 | uint CoprocessorIndex = (Opcode >> 8) & 0xf; 57 | int Rd = (int)((Opcode >> 12) & 0xf); 58 | int Rn = (int)((Opcode >> 16) & 0xf); 59 | } 60 | 61 | /// 62 | /// Move to Register from Coprocessor. 63 | /// 64 | private void ARM_MRC() 65 | { 66 | int CRm = (int)(Opcode & 0xf); 67 | uint Opcode2 = (Opcode >> 5) & 7; 68 | uint CoprocessorIndex = (Opcode >> 8) & 0xf; 69 | int Rd = (int)((Opcode >> 12) & 0xf); 70 | int CRn = (int)((Opcode >> 16) & 0xf); 71 | uint Opcode1 = (Opcode >> 21) & 7; 72 | 73 | if (CoprocessorIndex == 15) 74 | { 75 | uint Value = CP15.Read(CRn, Opcode1, CRm, Opcode2); 76 | 77 | if (Rd == 15) 78 | Registers.CPSR = (Registers.CPSR & 0xfffffff) | (Value & 0xf0000000); 79 | else 80 | Registers[Rd] = Value; 81 | } 82 | } 83 | 84 | /// 85 | /// Move to two Registers from Coprocessor. 86 | /// 87 | private void ARM_MRRC() 88 | { 89 | int CRm = (int)(Opcode & 0xf); 90 | uint CoprocessorOpcode = (Opcode >> 4) & 0xf; 91 | uint CoprocessorIndex = (Opcode >> 8) & 0xf; 92 | int Rd = (int)((Opcode >> 12) & 0xf); 93 | int Rn = (int)((Opcode >> 16) & 0xf); 94 | } 95 | 96 | /// 97 | /// Store Coprocessor. 98 | /// 99 | private void ARM_STC() 100 | { 101 | uint CoprocessorIndex = (Opcode >> 8) & 0xf; 102 | int CRd = (int)((Opcode >> 12) & 0xf); 103 | bool N = IsOpcodeBitSet(22); 104 | uint Address = ARM_GetLoadAndStoreCPAddress(); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/Exception.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SharpARM.ARM11 4 | { 5 | /// 6 | /// Arguments returned by the BKPT instruction. 7 | /// 8 | public class BreakpointEventArgs : EventArgs 9 | { 10 | /// 11 | /// Code set by the Program with the Break exception. 12 | /// 13 | public ushort BreakCode; 14 | 15 | /// 16 | /// Creates a new Breakpoint event argument with the given Break Code. 17 | /// 18 | /// 16-bits BKPT code set by the Program 19 | public BreakpointEventArgs(ushort BreakCode) 20 | { 21 | this.BreakCode = BreakCode; 22 | } 23 | } 24 | 25 | /// 26 | /// Arguments returned by the SWI instruction. 27 | /// 28 | public class SoftwareInterruptEventArgs : EventArgs 29 | { 30 | /// 31 | /// Code set by the Program with the Software Interrupt. 32 | /// 33 | public uint InterruptCode; 34 | 35 | /// 36 | /// Creates a new Software Interrupt event argument with the given Break Code. 37 | /// 38 | /// 24-bits SWI code set by the Program 39 | public SoftwareInterruptEventArgs(uint InterruptCode) 40 | { 41 | this.InterruptCode = InterruptCode; 42 | } 43 | } 44 | 45 | public partial class ARMCore 46 | { 47 | /// 48 | /// Breakpoint. 49 | /// 50 | private void ARM_BKPT() 51 | { 52 | uint SPSR = Registers.CPSR; 53 | Registers.Mode = ARMMode.Abort; 54 | Registers[14] = Registers[15] - 4; 55 | Registers.SPSR = SPSR; 56 | Registers.SetFlag(ARMFlag.Thumb, false); 57 | Registers.SetFlag(ARMFlag.IRQDisable, true); 58 | Registers.SetFlag(ARMFlag.AbortDisable, true); 59 | Registers.SetFlag(ARMFlag.Endianness, false); 60 | 61 | Registers[15] = HighVectors ? 0xffff000c : 0xc; 62 | 63 | if (OnBreakpoint != null) 64 | { 65 | ushort Code = (ushort)(((Opcode >> 4) & 0xfff0) | (Opcode & 0xf)); 66 | OnBreakpoint(this, new BreakpointEventArgs(Code)); 67 | } 68 | } 69 | 70 | /// 71 | /// Change Processor State. 72 | /// 73 | private void ARM_CPS() 74 | { 75 | ARMMode Mode = (ARMMode)(Opcode & 0x1f); 76 | bool mmod = IsOpcodeBitSet(17); 77 | uint imod = (Opcode >> 18) & 3; 78 | 79 | if ((imod & 2) != 0) 80 | { 81 | bool Value = (imod & 1) != 0; 82 | if (IsOpcodeBitSet(6)) Registers.SetFlag(ARMFlag.FIQDisable, Value); 83 | if (IsOpcodeBitSet(7)) Registers.SetFlag(ARMFlag.IRQDisable, Value); 84 | if (IsOpcodeBitSet(8)) Registers.SetFlag(ARMFlag.AbortDisable, Value); 85 | } 86 | else 87 | if (mmod) Registers.Mode = Mode; 88 | } 89 | 90 | /// 91 | /// Return from Exception. 92 | /// 93 | private void ARM_RFE() 94 | { 95 | uint Address = ARM_GetLoadAndStoreMultipleAddress(); 96 | 97 | Registers[15] = ReadUInt32(Address); 98 | if (Registers.Mode != ARMMode.User) Registers.CPSR = ReadUInt32(Address + 4); 99 | } 100 | 101 | /// 102 | /// Software Interrupt. 103 | /// 104 | private void ARM_SWI() 105 | { 106 | uint SPSR = Registers.CPSR; 107 | Registers.Mode = ARMMode.Supervisor; 108 | Registers[14] = Registers[15] - 4; 109 | Registers.SPSR = SPSR; 110 | Registers.SetFlag(ARMFlag.Thumb, false); 111 | Registers.SetFlag(ARMFlag.IRQDisable, true); 112 | Registers.SetFlag(ARMFlag.Endianness, false); 113 | 114 | Registers[15] = HighVectors ? 0xffff0008 : 8; 115 | 116 | if (OnSoftwareInterrupt != null) 117 | { 118 | uint Code = Opcode & 0xffffff; 119 | OnSoftwareInterrupt(this, new SoftwareInterruptEventArgs(Code)); 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/LoadAndStore.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | uint ExclusiveTag; 6 | bool ExclusiveEnabled; 7 | 8 | const uint ERGMask = 0xfffffff8; 9 | 10 | /// 11 | /// Preload Data. 12 | /// 13 | private void ARM_PLD() 14 | { 15 | uint Address = ARM_GetLoadAndStoreAddress(); 16 | 17 | //Nothing to do here... 18 | //But if you know how memory access may be optimized with PLD, go ahead and implement it! :) 19 | } 20 | 21 | /// 22 | /// Set Endian. 23 | /// 24 | private void ARM_SETEND() 25 | { 26 | Registers.SetFlag(ARMFlag.Endianness, IsOpcodeBitSet(9)); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/LoadAndStore/Load.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Load Multiple. 7 | /// 8 | private void ARM_LDM() 9 | { 10 | ushort RegisterList = (ushort)(Opcode & 0xffff); 11 | bool PC = (RegisterList & 0x8000) != 0; 12 | int Rn = (int)((Opcode >> 16) & 0xf); 13 | bool W = IsOpcodeBitSet(21); 14 | bool S = IsOpcodeBitSet(22); 15 | 16 | ARMMode OldMode = Registers.Mode; 17 | if (S && !PC) Registers.Mode = ARMMode.User; 18 | uint Address = ARM_GetLoadAndStoreMultipleAddress() & 0xfffffffc; 19 | for (int Index = 0; Index < 15; Index++) 20 | { 21 | if ((RegisterList & (1 << Index)) != 0) 22 | { 23 | Registers[Index] = ReadUInt32E(Address); 24 | Address += 4; 25 | } 26 | } 27 | Registers.Mode = OldMode; 28 | 29 | if (PC) 30 | { 31 | uint Value = ReadUInt32E(Address); 32 | Registers[15] = Value & 0xfffffffe; 33 | Registers.SetFlag(ARMFlag.Thumb, (Value & 1) != 0); 34 | if (S) Registers.CPSR = Registers.SPSR; 35 | } 36 | } 37 | 38 | /// 39 | /// Load Register. 40 | /// 41 | private void ARM_LDR() 42 | { 43 | int Rd = (int)((Opcode >> 12) & 0xf); 44 | 45 | uint Address = ARM_GetLoadAndStoreAddress(); 46 | uint Value = ROR(ReadUInt32E(Address & 0xfffffffc), (int)(Address & 3) << 3); 47 | if (Rd == 15) 48 | { 49 | Registers[15] = Value & 0xfffffffe; 50 | Registers.SetFlag(ARMFlag.Thumb, (Value & 1) != 0); 51 | } 52 | else 53 | Registers[Rd] = Value; 54 | } 55 | 56 | /// 57 | /// Load Register Byte. 58 | /// 59 | private void ARM_LDRB() 60 | { 61 | int Rd = (int)((Opcode >> 12) & 0xf); 62 | 63 | uint Address = ARM_GetLoadAndStoreAddress(); 64 | byte Value = Bus.ReadUInt8(Address); 65 | Registers[Rd] = Value; 66 | } 67 | 68 | /// 69 | /// Load Register Doubleword. 70 | /// 71 | private void ARM_LDRD() 72 | { 73 | int Rd = (int)((Opcode >> 12) & 0xf); 74 | 75 | if (Rd != 15) 76 | { 77 | uint Address = ARM_GetLoadAndStoreNonWordAddress(); 78 | Registers[Rd] = ReadUInt32E(Address); 79 | Registers[Rd + 1] = ReadUInt32E(Address + 4); 80 | } 81 | } 82 | 83 | /// 84 | /// Load Register Exclusive. 85 | /// 86 | private void ARM_LDREX() 87 | { 88 | int Rd = (int)((Opcode >> 12) & 0xf); 89 | int Rn = (int)((Opcode >> 16) & 0xf); 90 | 91 | uint Address = Registers[Rn]; 92 | uint Value = ReadUInt32E(Address); 93 | Registers[Rd] = Value; 94 | ExclusiveTag = Address & ERGMask; 95 | ExclusiveEnabled = true; 96 | } 97 | 98 | /// 99 | /// Load Register Halfword. 100 | /// 101 | private void ARM_LDRH() 102 | { 103 | int Rd = (int)((Opcode >> 12) & 0xf); 104 | 105 | uint Address = ARM_GetLoadAndStoreNonWordAddress(); 106 | Registers[Rd] = ReadUInt16E(Address); 107 | } 108 | 109 | /// 110 | /// Load Register Signed Byte. 111 | /// 112 | private void ARM_LDRSB() 113 | { 114 | int Rd = (int)((Opcode >> 12) & 0xf); 115 | 116 | uint Address = ARM_GetLoadAndStoreNonWordAddress(); 117 | sbyte Value = (sbyte)Bus.ReadUInt8(Address); 118 | Registers[Rd] = (uint)Value; 119 | } 120 | 121 | /// 122 | /// Load Register Signed Halfword. 123 | /// 124 | private void ARM_LDRSH() 125 | { 126 | int Rd = (int)((Opcode >> 12) & 0xf); 127 | 128 | uint Address = ARM_GetLoadAndStoreNonWordAddress(); 129 | short Value = (short)ReadUInt16E(Address); 130 | Registers[Rd] = (uint)Value; 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/LoadAndStore/Store.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Store Return State. 7 | /// 8 | private void ARM_SRS() 9 | { 10 | uint Address = ARM_GetSRSAddress(); 11 | 12 | ARMMode OldMode = Registers.Mode; 13 | Registers.Mode = (ARMMode)(Opcode & 0x1f); 14 | 15 | WriteUInt32E(Address, Registers[14]); 16 | WriteUInt32E(Address + 4, Registers.SPSR); 17 | 18 | Registers.Mode = OldMode; 19 | } 20 | 21 | /// 22 | /// Store Multiple. 23 | /// 24 | private void ARM_STM() 25 | { 26 | ushort RegisterList = (ushort)(Opcode & 0xffff); 27 | int Rn = (int)((Opcode >> 16) & 0xf); 28 | bool W = IsOpcodeBitSet(21); 29 | bool S = IsOpcodeBitSet(22); 30 | bool U = IsOpcodeBitSet(23); 31 | bool P = IsOpcodeBitSet(24); 32 | 33 | uint Address; 34 | if (U) 35 | Address = Registers[Rn] + (uint)(P ? 4 : 0); 36 | else 37 | { 38 | Address = Registers[Rn] + (uint)(P ? 0 : 4); 39 | for (int Index = 0; Index < 16; Index++) 40 | { 41 | if ((RegisterList & (1 << Index)) != 0) Address -= 4; 42 | } 43 | } 44 | 45 | uint Count = 0; 46 | ARMMode OldMode = Registers.Mode; 47 | if (S) Registers.Mode = ARMMode.User; 48 | for (int Index = 0; Index < 16; Index++) 49 | { 50 | if ((RegisterList & (1 << Index)) != 0) 51 | { 52 | WriteUInt32E(Address + Count, Registers[Index]); 53 | Count += 4; 54 | } 55 | } 56 | Registers.Mode = OldMode; 57 | 58 | if (W) 59 | { 60 | if (U) 61 | Registers[Rn] += Count; 62 | else 63 | Registers[Rn] -= Count; 64 | } 65 | } 66 | 67 | /// 68 | /// Store Register. 69 | /// 70 | private void ARM_STR() 71 | { 72 | int Rd = (int)((Opcode >> 12) & 0xf); 73 | 74 | uint Address = ARM_GetLoadAndStoreAddress(); 75 | uint Value = ReadUInt32E(Address); 76 | WriteUInt32E(Address, Registers[Rd]); 77 | } 78 | 79 | /// 80 | /// Store Register Byte. 81 | /// 82 | private void ARM_STRB() 83 | { 84 | int Rd = (int)((Opcode >> 12) & 0xf); 85 | 86 | uint Address = ARM_GetLoadAndStoreAddress(); 87 | Bus.WriteUInt8(Address, (byte)Registers[Rd]); 88 | } 89 | 90 | /// 91 | /// Store Register Doubleword. 92 | /// 93 | private void ARM_STRD() 94 | { 95 | int Rd = (int)((Opcode >> 12) & 0xf); 96 | 97 | if (Rd != 15) 98 | { 99 | uint Address = ARM_GetLoadAndStoreNonWordAddress(); 100 | WriteUInt32E(Address, Registers[Rd]); 101 | WriteUInt32E(Address + 4, Registers[Rd + 1]); 102 | } 103 | } 104 | 105 | /// 106 | /// Store Register Exclusive. 107 | /// 108 | private void ARM_STREX() 109 | { 110 | int Rm = (int)(Opcode & 0xf); 111 | int Rd = (int)((Opcode >> 12) & 0xf); 112 | int Rn = (int)((Opcode >> 16) & 0xf); 113 | 114 | uint Address = Registers[Rn]; 115 | if (ExclusiveEnabled && ExclusiveTag == (Address & ERGMask)) 116 | { 117 | WriteUInt32E(Address, Registers[Rm]); 118 | ExclusiveEnabled = false; 119 | Registers[Rd] = 0; 120 | } 121 | else 122 | Registers[Rd] = 1; 123 | } 124 | 125 | /// 126 | /// Store Register Halfword. 127 | /// 128 | private void ARM_STRH() 129 | { 130 | int Rd = (int)((Opcode >> 12) & 0xf); 131 | 132 | uint Address = ARM_GetLoadAndStoreNonWordAddress(); 133 | WriteUInt16E(Address, (ushort)Registers[Rd]); 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/Logical.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// And. 7 | /// 8 | private void ARM_AND() 9 | { 10 | int Rd = (int)((Opcode >> 12) & 0xf); 11 | int Rn = (int)((Opcode >> 16) & 0xf); 12 | bool S = IsOpcodeBitSet(20); 13 | uint ShifterOperand = ARM_GetShifterOperand(S && Rd != 15); 14 | 15 | Registers[Rd] = Registers[Rn] & ShifterOperand; 16 | 17 | if (S) 18 | { 19 | if (Rd != 15) 20 | SetZNFlags(Registers[Rd]); 21 | else 22 | Registers.CPSR = Registers.SPSR; 23 | } 24 | } 25 | 26 | /// 27 | /// Bit Clear. 28 | /// 29 | private void ARM_BIC() 30 | { 31 | int Rd = (int)((Opcode >> 12) & 0xf); 32 | int Rn = (int)((Opcode >> 16) & 0xf); 33 | bool S = IsOpcodeBitSet(20); 34 | uint ShifterOperand = ARM_GetShifterOperand(S && Rd != 15); 35 | 36 | Registers[Rd] = Registers[Rn] & ~ShifterOperand; 37 | 38 | if (S) 39 | { 40 | if (Rd != 15) 41 | SetZNFlags(Registers[Rd]); 42 | else 43 | Registers.CPSR = Registers.SPSR; 44 | } 45 | } 46 | 47 | /// 48 | /// Count Leading Zeros. 49 | /// 50 | private void ARM_CLZ() 51 | { 52 | int Rm = (int)(Opcode & 0xf); 53 | int Rd = (int)((Opcode >> 12) & 0xf); 54 | 55 | if (Registers[Rm] == 0) 56 | Registers[Rd] = 32; 57 | else 58 | { 59 | for (int Count = 31; Count >= 0; Count--) 60 | { 61 | if ((Registers[Rm] & (1 << Count)) != 0) 62 | { 63 | Registers[Rd] = (uint)(31 - Count); 64 | break; 65 | } 66 | } 67 | } 68 | } 69 | 70 | /// 71 | /// Exclusive Or. 72 | /// 73 | private void ARM_EOR() 74 | { 75 | int Rd = (int)((Opcode >> 12) & 0xf); 76 | int Rn = (int)((Opcode >> 16) & 0xf); 77 | bool S = IsOpcodeBitSet(20); 78 | uint ShifterOperand = ARM_GetShifterOperand(S && Rd != 15); 79 | 80 | Registers[Rd] = Registers[Rn] ^ ShifterOperand; 81 | 82 | if (S) 83 | { 84 | if (Rd != 15) 85 | SetZNFlags(Registers[Rd]); 86 | else 87 | Registers.CPSR = Registers.SPSR; 88 | } 89 | } 90 | 91 | /// 92 | /// Or. 93 | /// 94 | private void ARM_ORR() 95 | { 96 | int Rd = (int)((Opcode >> 12) & 0xf); 97 | int Rn = (int)((Opcode >> 16) & 0xf); 98 | bool S = IsOpcodeBitSet(20); 99 | uint ShifterOperand = ARM_GetShifterOperand(S && Rd != 15); 100 | 101 | Registers[Rd] = Registers[Rn] | ShifterOperand; 102 | 103 | if (S) 104 | { 105 | if (Rd != 15) 106 | SetZNFlags(Registers[Rd]); 107 | else 108 | Registers.CPSR = Registers.SPSR; 109 | } 110 | } 111 | 112 | /// 113 | /// Pack Halfword Bottom Top. 114 | /// 115 | private void ARM_PKHBT() 116 | { 117 | int Rm = (int)(Opcode & 0xf); 118 | int ShiftImmediate = (int)((Opcode >> 7) & 0x1f); 119 | int Rd = (int)((Opcode >> 12) & 0xf); 120 | int Rn = (int)((Opcode >> 16) & 0xf); 121 | 122 | Registers[Rd] = (Registers[Rn] & 0xffff); 123 | Registers[Rd] |= ((Registers[Rm] << ShiftImmediate) & 0xffff0000); 124 | } 125 | 126 | /// 127 | /// Pack Halfword Top Bottom. 128 | /// 129 | private void ARM_PKHTB() 130 | { 131 | int Rm = (int)(Opcode & 0xf); 132 | int ShiftImmediate = (int)((Opcode >> 7) & 0x1f); 133 | int Rd = (int)((Opcode >> 12) & 0xf); 134 | int Rn = (int)((Opcode >> 16) & 0xf); 135 | 136 | Registers[Rd] = (Registers[Rn] & 0xffff0000); 137 | 138 | if (ShiftImmediate == 0) 139 | Registers[Rd] |= (uint)((Registers[Rm] & 0x80000000) != 0 ? 0xffff : 0); 140 | else 141 | Registers[Rd] |= ((Registers[Rm] >> ShiftImmediate) & 0xffff); 142 | } 143 | 144 | /// 145 | /// Byte-Reverse Word. 146 | /// 147 | private void ARM_REV() 148 | { 149 | int Rm = (int)(Opcode & 0xf); 150 | int Rd = (int)((Opcode >> 12) & 0xf); 151 | 152 | Registers[Rd] = (Registers[Rm] >> 24) | 153 | ((Registers[Rm] >> 8) & 0xff00) | 154 | ((Registers[Rm] & 0xff00) << 8) | 155 | ((Registers[Rm] & 0xff) << 24); 156 | } 157 | 158 | /// 159 | /// Byte-Reverse Packed Halfword. 160 | /// 161 | private void ARM_REV16() 162 | { 163 | int Rm = (int)(Opcode & 0xf); 164 | int Rd = (int)((Opcode >> 12) & 0xf); 165 | 166 | Registers[Rd] = ((Registers[Rm] >> 8) & 0xff0000) | 167 | ((Registers[Rm] & 0xff0000) << 8) | 168 | ((Registers[Rm] >> 8) & 0xff) | 169 | ((Registers[Rm] & 0xff) << 8); 170 | } 171 | 172 | /// 173 | /// Byte-Reverse Signed Halfword. 174 | /// 175 | private void ARM_REVSH() 176 | { 177 | int Rm = (int)(Opcode & 0xf); 178 | int Rd = (int)((Opcode >> 12) & 0xf); 179 | 180 | Registers[Rd] = ((Registers[Rm] >> 8) & 0xff) | ((Registers[Rm] & 0xff) << 8); 181 | if ((Registers[Rm] & 0x80) != 0) Registers[Rd] |= 0xffff0000; 182 | } 183 | 184 | /// 185 | /// Select. 186 | /// 187 | private void ARM_SEL() 188 | { 189 | int Rm = (int)(Opcode & 0xf); 190 | int Rd = (int)((Opcode >> 12) & 0xf); 191 | int Rn = (int)((Opcode >> 16) & 0xf); 192 | 193 | Registers[Rd] = (Registers.GE & 1) != 0 ? Registers[Rn] & 0xff : Registers[Rm] & 0xff; 194 | Registers[Rd] |= (Registers.GE & 2) != 0 ? Registers[Rn] & 0xff00 : Registers[Rm] & 0xff00; 195 | Registers[Rd] |= (Registers.GE & 4) != 0 ? Registers[Rn] & 0xff0000 : Registers[Rm] & 0xff0000; 196 | Registers[Rd] |= (Registers.GE & 8) != 0 ? Registers[Rn] & 0xff000000 : Registers[Rm] & 0xff000000; 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/ARM/Move.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | const uint UserMask = 0xf80f0200; 6 | const uint PrivilegedMask = 0x1df; 7 | const uint StateMask = 0x1000020; 8 | 9 | /// 10 | /// Move. 11 | /// 12 | private void ARM_MOV() 13 | { 14 | int Rd = (int)((Opcode >> 12) & 0xf); 15 | bool S = IsOpcodeBitSet(20); 16 | uint ShifterOperand = ARM_GetShifterOperand(S && Rd != 15); 17 | 18 | Registers[Rd] = ShifterOperand; 19 | if (S) 20 | { 21 | if (Rd != 15) 22 | SetZNFlags(Registers[Rd]); 23 | else 24 | Registers.CPSR = Registers.SPSR; 25 | } 26 | } 27 | 28 | /// 29 | /// Move General-Purpose Register to Status Register. 30 | /// 31 | private void ARM_MRS() 32 | { 33 | int Rd = (int)((Opcode >> 12) & 0xf); 34 | bool R = IsOpcodeBitSet(22); 35 | 36 | Registers[Rd] = R ? Registers.SPSR : Registers.CPSR; 37 | } 38 | 39 | /// 40 | /// Move Status Register to General-Purpose Register. 41 | /// 42 | private void ARM_MSR() 43 | { 44 | uint Mask = (Opcode >> 16) & 0xf; 45 | bool R = IsOpcodeBitSet(22); 46 | bool I = IsOpcodeBitSet(25); 47 | 48 | uint ByteMask = 0; 49 | if ((Mask & 1) != 0) ByteMask |= 0xff; 50 | if ((Mask & 2) != 0) ByteMask |= 0xff00; 51 | if ((Mask & 4) != 0) ByteMask |= 0xff0000; 52 | if ((Mask & 8) != 0) ByteMask |= 0xff000000; 53 | 54 | uint Value; 55 | if (I) 56 | { 57 | uint Immediate = Opcode & 0xff; 58 | int Rotate = (int)((Opcode >> 7) & 0x1e); 59 | Value = ROR(Immediate, Rotate); 60 | } 61 | else 62 | { 63 | int Rm = (int)(Opcode & 0xf); 64 | Value = Registers[Rm]; 65 | } 66 | 67 | if (R) 68 | { 69 | Mask = ByteMask & (UserMask | PrivilegedMask | StateMask); 70 | Registers.SPSR = (Registers.SPSR & ~Mask) | (Value & Mask); 71 | } 72 | else 73 | { 74 | Mask = ByteMask & (Registers.Mode == ARMMode.User ? UserMask : UserMask | PrivilegedMask); 75 | Registers.CPSR = (Registers.CPSR & ~Mask) | (Value & Mask); 76 | } 77 | } 78 | 79 | /// 80 | /// Move Not. 81 | /// 82 | private void ARM_MVN() 83 | { 84 | int Rd = (int)((Opcode >> 12) & 0xf); 85 | bool S = IsOpcodeBitSet(20); 86 | uint ShifterOperand = ARM_GetShifterOperand(S && Rd != 15); 87 | 88 | Registers[Rd] = ~ShifterOperand; 89 | if (S) 90 | { 91 | if (Rd != 15) 92 | SetZNFlags(Registers[Rd]); 93 | else 94 | Registers.CPSR = Registers.SPSR; 95 | } 96 | } 97 | 98 | /// 99 | /// Swap. 100 | /// 101 | private void ARM_SWP() 102 | { 103 | int Rm = (int)(Opcode & 0xf); 104 | int Rd = (int)((Opcode >> 12) & 0xf); 105 | int Rn = (int)((Opcode >> 16) & 0xf); 106 | 107 | uint Value = ReadUInt32E(Registers[Rn]); 108 | WriteUInt32E(Registers[Rn], Registers[Rm]); 109 | Registers[Rd] = Value; 110 | } 111 | 112 | /// 113 | /// Swap Byte. 114 | /// 115 | private void ARM_SWPB() 116 | { 117 | int Rm = (int)(Opcode & 0xf); 118 | int Rd = (int)((Opcode >> 12) & 0xf); 119 | int Rn = (int)((Opcode >> 16) & 0xf); 120 | 121 | byte Value = Bus.ReadUInt8(Registers[Rn]); 122 | Bus.WriteUInt8(Registers[Rn], (byte)Registers[Rm]); 123 | Registers[Rd] = Value; 124 | } 125 | 126 | /// 127 | /// Signed Extend Accumulate Byte. 128 | /// 129 | private void ARM_SXTAB() 130 | { 131 | int Rm = (int)(Opcode & 0xf); 132 | int Rotate = (int)((Opcode >> 10) & 3); 133 | int Rd = (int)((Opcode >> 12) & 0xf); 134 | int Rn = (int)((Opcode >> 16) & 0xf); 135 | 136 | uint Operand = ROR(Registers[Rm], Rotate << 3); 137 | Registers[Rd] = (uint)(Registers[Rn] + (sbyte)Operand); 138 | } 139 | 140 | /// 141 | /// Signed Extend Accumulate Byte 16-bits. 142 | /// 143 | private void ARM_SXTAB16() 144 | { 145 | int Rm = (int)(Opcode & 0xf); 146 | int Rotate = (int)((Opcode >> 10) & 3); 147 | int Rd = (int)((Opcode >> 12) & 0xf); 148 | int Rn = (int)((Opcode >> 16) & 0xf); 149 | 150 | uint Operand = ROR(Registers[Rm], Rotate << 3); 151 | Registers[Rd] = (ushort)(Registers[Rn] + (sbyte)Operand); 152 | Registers[Rd] |= (uint)((Registers[Rn] + (sbyte)(Operand >> 16)) << 16); 153 | } 154 | 155 | /// 156 | /// Signed Extend Accumulate Halfword. 157 | /// 158 | private void ARM_SXTAH() 159 | { 160 | int Rm = (int)(Opcode & 0xf); 161 | int Rotate = (int)((Opcode >> 10) & 3); 162 | int Rd = (int)((Opcode >> 12) & 0xf); 163 | int Rn = (int)((Opcode >> 16) & 0xf); 164 | 165 | uint Operand = ROR(Registers[Rm], Rotate << 3); 166 | Registers[Rd] = (uint)(Registers[Rn] + (short)Operand); 167 | } 168 | 169 | /// 170 | /// Signed Extend Byte. 171 | /// 172 | private void ARM_SXTB() 173 | { 174 | int Rm = (int)(Opcode & 0xf); 175 | int Rotate = (int)((Opcode >> 10) & 3); 176 | int Rd = (int)((Opcode >> 12) & 0xf); 177 | 178 | sbyte Operand = (sbyte)ROR(Registers[Rm], Rotate << 3); 179 | Registers[Rd] = (uint)Operand; 180 | } 181 | 182 | /// 183 | /// Signed Extend Byte 16-bits. 184 | /// 185 | private void ARM_SXTB16() 186 | { 187 | int Rm = (int)(Opcode & 0xf); 188 | int Rotate = (int)((Opcode >> 10) & 3); 189 | int Rd = (int)((Opcode >> 12) & 0xf); 190 | int Rn = (int)((Opcode >> 16) & 0xf); 191 | 192 | uint Operand = ROR(Registers[Rm], Rotate << 3); 193 | Registers[Rd] = (ushort)((short)Operand); 194 | Registers[Rd] |= (uint)((short)(Operand >> 16) << 16); 195 | } 196 | 197 | /// 198 | /// Signed Extend Halfword. 199 | /// 200 | private void ARM_SXTH() 201 | { 202 | int Rm = (int)(Opcode & 0xf); 203 | int Rotate = (int)((Opcode >> 10) & 3); 204 | int Rd = (int)((Opcode >> 12) & 0xf); 205 | int Rn = (int)((Opcode >> 16) & 0xf); 206 | 207 | short Operand = (short)ROR(Registers[Rm], Rotate << 3); 208 | Registers[Rd] = (uint)Operand; 209 | } 210 | 211 | /// 212 | /// Unsigned Extend Accumulate Byte. 213 | /// 214 | private void ARM_UXTAB() 215 | { 216 | int Rm = (int)(Opcode & 0xf); 217 | int Rotate = (int)((Opcode >> 10) & 3); 218 | int Rd = (int)((Opcode >> 12) & 0xf); 219 | int Rn = (int)((Opcode >> 16) & 0xf); 220 | 221 | uint Operand = ROR(Registers[Rm], Rotate << 3); 222 | Registers[Rd] = Registers[Rn] + (byte)Operand; 223 | } 224 | 225 | /// 226 | /// Unsigned Extend Accumulate Byte 16-bits. 227 | /// 228 | private void ARM_UXTAB16() 229 | { 230 | int Rm = (int)(Opcode & 0xf); 231 | int Rotate = (int)((Opcode >> 10) & 3); 232 | int Rd = (int)((Opcode >> 12) & 0xf); 233 | int Rn = (int)((Opcode >> 16) & 0xf); 234 | 235 | uint Operand = ROR(Registers[Rm], Rotate << 3); 236 | Registers[Rd] = (ushort)(Registers[Rn] + (byte)Operand); 237 | Registers[Rd] |= (Registers[Rn] + (byte)(Operand >> 16)) << 16; 238 | } 239 | 240 | /// 241 | /// Unsigned Extend Accumulate Halfword. 242 | /// 243 | private void ARM_UXTAH() 244 | { 245 | int Rm = (int)(Opcode & 0xf); 246 | int Rotate = (int)((Opcode >> 10) & 3); 247 | int Rd = (int)((Opcode >> 12) & 0xf); 248 | int Rn = (int)((Opcode >> 16) & 0xf); 249 | 250 | uint Operand = ROR(Registers[Rm], Rotate << 3); 251 | Registers[Rd] = Registers[Rn] + (ushort)Operand; 252 | } 253 | 254 | /// 255 | /// Unsigned Extend Byte. 256 | /// 257 | private void ARM_UXTB() 258 | { 259 | int Rm = (int)(Opcode & 0xf); 260 | int Rotate = (int)((Opcode >> 10) & 3); 261 | int Rd = (int)((Opcode >> 12) & 0xf); 262 | 263 | Registers[Rd] = ROR(Registers[Rm], Rotate << 3) & 0xff; 264 | } 265 | 266 | /// 267 | /// Unsigned Extend Byte 16-bits. 268 | /// 269 | private void ARM_UXTB16() 270 | { 271 | int Rm = (int)(Opcode & 0xf); 272 | int Rotate = (int)((Opcode >> 10) & 3); 273 | int Rd = (int)((Opcode >> 12) & 0xf); 274 | int Rn = (int)((Opcode >> 16) & 0xf); 275 | 276 | Registers[Rd] = ROR(Registers[Rm], Rotate << 3) & 0xff00ff; 277 | } 278 | 279 | /// 280 | /// Unsigned Extend Halfword. 281 | /// 282 | private void ARM_UXTH() 283 | { 284 | int Rm = (int)(Opcode & 0xf); 285 | int Rotate = (int)((Opcode >> 10) & 3); 286 | int Rd = (int)((Opcode >> 12) & 0xf); 287 | int Rn = (int)((Opcode >> 16) & 0xf); 288 | 289 | Registers[Rd] = ROR(Registers[Rm], Rotate << 3) & 0xffff; 290 | } 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/Thumb/Arithmetic.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | //Addition 6 | 7 | /// 8 | /// Add with Carry. 9 | /// 10 | private void Thumb_ADC() 11 | { 12 | int Rd = (int)(Opcode & 7); 13 | int Rm = (int)((Opcode >> 3) & 7); 14 | 15 | Registers[Rd] = Add(Registers[Rd], Registers[Rm], true, true); 16 | } 17 | 18 | /// 19 | /// Add (1). 20 | /// 21 | private void Thumb_ADD() 22 | { 23 | int Rd = (int)(Opcode & 7); 24 | int Rn = (int)((Opcode >> 3) & 7); 25 | uint Immediate = (Opcode >> 6) & 7; 26 | 27 | Registers[Rd] = Add(Registers[Rn], Immediate, false, true); 28 | } 29 | 30 | /// 31 | /// Add (2). 32 | /// 33 | private void Thumb_ADD_2() 34 | { 35 | uint Immediate = Opcode & 0xff; 36 | int Rd = (int)((Opcode >> 8) & 7); 37 | 38 | Registers[Rd] = Add(Registers[Rd], Immediate, false, true); 39 | } 40 | 41 | /// 42 | /// Add (3). 43 | /// 44 | private void Thumb_ADD_3() 45 | { 46 | int Rd = (int)(Opcode & 7); 47 | int Rn = (int)((Opcode >> 3) & 7); 48 | int Rm = (int)((Opcode >> 6) & 7); 49 | 50 | Registers[Rd] = Add(Registers[Rn], Registers[Rm], false, true); 51 | } 52 | 53 | /// 54 | /// Add (4). 55 | /// 56 | private void Thumb_ADD_4() 57 | { 58 | int Rd = (int)(Opcode & 7); 59 | int Rm = (int)((Opcode >> 3) & 7); 60 | 61 | if (IsOpcodeBitSet(7)) Rd += 8; 62 | if (IsOpcodeBitSet(6)) Rm += 8; 63 | Registers[Rd] = Add(Registers[Rd], Registers[Rm], false, false); 64 | } 65 | 66 | /// 67 | /// Add (5). 68 | /// 69 | private void Thumb_ADD_5() 70 | { 71 | uint Immediate = Opcode & 0xff; 72 | int Rd = (int)((Opcode >> 8) & 7); 73 | 74 | Registers[Rd] = Add(Registers[15] & 0xfffffffc, Immediate << 2, false, false); 75 | } 76 | 77 | /// 78 | /// Add (6). 79 | /// 80 | private void Thumb_ADD_6() 81 | { 82 | uint Immediate = Opcode & 0xff; 83 | int Rd = (int)((Opcode >> 8) & 7); 84 | 85 | Registers[Rd] = Add(Registers[13], Immediate << 2, false, false); 86 | } 87 | 88 | /// 89 | /// Add (7). 90 | /// 91 | private void Thumb_ADD_7() 92 | { 93 | uint Immediate = Opcode & 0x7f; 94 | 95 | Registers[13] = Add(Registers[13], Immediate << 2, false, false); 96 | } 97 | 98 | //Miscellaneous 99 | 100 | /// 101 | /// Arithmetic Shift Right (1). 102 | /// 103 | private void Thumb_ASR() 104 | { 105 | int Rd = (int)(Opcode & 7); 106 | int Rm = (int)((Opcode >> 3) & 7); 107 | int Shift = (int)((Opcode >> 6) & 0x1f); 108 | 109 | if (Shift == 0) Shift = 32; 110 | int RmValue = (int)Registers[Rm]; 111 | Registers[Rd] = (uint)((long)RmValue >> Shift); 112 | Registers.SetFlag(ARMFlag.Carry, (RmValue & (1 << (Shift - 1))) != 0); 113 | 114 | SetZNFlags(Registers[Rd]); 115 | } 116 | 117 | /// 118 | /// Arithmetic Shift Right (2). 119 | /// 120 | private void Thumb_ASR_2() 121 | { 122 | int Rd = (int)(Opcode & 7); 123 | int Rs = (int)((Opcode >> 3) & 7); 124 | 125 | int Shift = (int)(Registers[Rs] & 0xff); 126 | if (Shift > 0) 127 | { 128 | bool Carry = false; 129 | if (Shift <= 32) 130 | { 131 | int RdValue = (int)Registers[Rd]; 132 | Registers[Rd] = (uint)((long)RdValue >> Shift); 133 | Carry = (RdValue & (1 << (Shift - 1))) != 0; 134 | } 135 | else 136 | { 137 | Carry = (Registers[Rd] & 0x80000000) != 0; 138 | Registers[Rd] = Carry ? 0xffffffff : 0; 139 | } 140 | 141 | Registers.SetFlag(ARMFlag.Carry, Carry); 142 | } 143 | 144 | SetZNFlags(Registers[Rd]); 145 | } 146 | 147 | /// 148 | /// Multiply. 149 | /// 150 | private void Thumb_MUL() 151 | { 152 | int Rd = (int)(Opcode & 7); 153 | int Rm = (int)((Opcode >> 3) & 7); 154 | 155 | Registers[Rd] *= Registers[Rm]; 156 | SetZNFlags(Registers[Rd]); 157 | } 158 | 159 | //Subtraction 160 | 161 | /// 162 | /// Negate. 163 | /// 164 | private void Thumb_NEG() 165 | { 166 | int Rd = (int)(Opcode & 7); 167 | int Rm = (int)((Opcode >> 3) & 7); 168 | 169 | Registers[Rd] = Subtract(0, Registers[Rm], false, true); 170 | } 171 | 172 | /// 173 | /// Subtract with Carry. 174 | /// 175 | private void Thumb_SBC() 176 | { 177 | int Rd = (int)(Opcode & 7); 178 | int Rm = (int)((Opcode >> 3) & 7); 179 | 180 | Registers[Rd] = Subtract(Registers[Rd], Registers[Rm], true, true); 181 | } 182 | 183 | /// 184 | /// Subtract (1). 185 | /// 186 | private void Thumb_SUB() 187 | { 188 | int Rd = (int)(Opcode & 7); 189 | int Rn = (int)((Opcode >> 3) & 7); 190 | uint Immediate = (Opcode >> 6) & 7; 191 | 192 | Registers[Rd] = Subtract(Registers[Rn], Immediate, false, true); 193 | } 194 | 195 | /// 196 | /// Subtract (2). 197 | /// 198 | private void Thumb_SUB_2() 199 | { 200 | uint Immediate = Opcode & 0xff; 201 | int Rd = (int)((Opcode >> 8) & 7); 202 | 203 | Registers[Rd] = Subtract(Registers[Rd], Immediate, false, true); 204 | } 205 | 206 | /// 207 | /// Subtract (3). 208 | /// 209 | private void Thumb_SUB_3() 210 | { 211 | int Rd = (int)(Opcode & 7); 212 | int Rn = (int)((Opcode >> 3) & 7); 213 | int Rm = (int)((Opcode >> 6) & 7); 214 | 215 | Registers[Rd] = Subtract(Registers[Rn], Registers[Rm], false, true); 216 | } 217 | 218 | /// 219 | /// Subtract (4). 220 | /// 221 | private void Thumb_SUB_4() 222 | { 223 | uint Immediate = Opcode & 0x7f; 224 | 225 | Registers[13] = Subtract(Registers[13], Immediate << 2, false, false); 226 | } 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/Thumb/Branch.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Branch (1). 7 | /// 8 | private void Thumb_B() 9 | { 10 | sbyte Immediate = (sbyte)(Opcode & 0xff); 11 | 12 | ARMCondition Condition = (ARMCondition)((Opcode >> 8) & 0xf); 13 | if (IsConditionMet(Condition)) Registers[15] = (uint)(Registers[15] + (Immediate << 1)); 14 | } 15 | 16 | /// 17 | /// Branch (2). 18 | /// 19 | private void Thumb_B_2() 20 | { 21 | int Immediate = SignExtend12((Opcode & 0x7ff) << 1); 22 | 23 | Registers[15] = (uint)(Registers[15] + Immediate); 24 | } 25 | 26 | /// 27 | /// Branch with Link and Exchange (1). 28 | /// 29 | private void Thumb_BLX() 30 | { 31 | uint Immediate = Opcode & 0x7ff; 32 | uint H = (Opcode >> 11) & 3; 33 | 34 | if (H > 0) 35 | { 36 | if (H != 2) 37 | { 38 | uint LR = (Registers[15] - 2) | 1; 39 | Registers[15] = Registers[14] + (Immediate << 1); 40 | Registers[14] = LR; 41 | 42 | if (H == 1) 43 | { 44 | Registers[15] &= 0xfffffffc; 45 | Registers.SetFlag(ARMFlag.Thumb, false); 46 | } 47 | } 48 | else 49 | Registers[14] = (uint)(Registers[15] + (SignExtend11(Immediate) << 12)); 50 | } 51 | } 52 | 53 | /// 54 | /// Branch with Link and Exchange (2). 55 | /// 56 | private void Thumb_BLX_2() 57 | { 58 | int Rm = (int)((Opcode >> 3) & 7); 59 | 60 | Registers[14] = (Registers[15] - 2) | 1; 61 | Registers[15] = Registers[Rm] & 0xfffffffe; 62 | Registers.SetFlag(ARMFlag.Thumb, (Registers[Rm] & 1) != 0); 63 | } 64 | 65 | /// 66 | /// Branch and Exchange. 67 | /// 68 | private void Thumb_BX() 69 | { 70 | int Rm = (int)((Opcode >> 3) & 0xf); 71 | 72 | Registers[15] = Registers[Rm] & 0xfffffffe; 73 | Registers.SetFlag(ARMFlag.Thumb, (Registers[Rm] & 1) != 0); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/Thumb/Compare.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Compare Negative. 7 | /// 8 | private void Thumb_CMN() 9 | { 10 | int Rn = (int)(Opcode & 7); 11 | int Rm = (int)((Opcode >> 3) & 7); 12 | 13 | Add(Registers[Rn], Registers[Rm], false, true); 14 | } 15 | 16 | /// 17 | /// Compare (1). 18 | /// 19 | private void Thumb_CMP() 20 | { 21 | uint Immediate = Opcode & 0xff; 22 | int Rn = (int)((Opcode >> 8) & 7); 23 | 24 | Subtract(Registers[Rn], Immediate, false, true); 25 | } 26 | 27 | /// 28 | /// Compare (2). 29 | /// 30 | private void Thumb_CMP_2() 31 | { 32 | int Rn = (int)(Opcode & 7); 33 | int Rm = (int)((Opcode >> 3) & 7); 34 | 35 | Subtract(Registers[Rn], Registers[Rm], false, true); 36 | } 37 | 38 | /// 39 | /// Compare (3). 40 | /// 41 | private void Thumb_CMP_3() 42 | { 43 | int Rn = (int)(Opcode & 7); 44 | int Rm = (int)((Opcode >> 3) & 7); 45 | 46 | if (IsOpcodeBitSet(7)) Rn += 8; 47 | if (IsOpcodeBitSet(6)) Rm += 8; 48 | Subtract(Registers[Rn], Registers[Rm], false, true); 49 | } 50 | 51 | /// 52 | /// Test. 53 | /// 54 | private void Thumb_TST() 55 | { 56 | int Rn = (int)(Opcode & 7); 57 | int Rm = (int)((Opcode >> 3) & 7); 58 | 59 | SetZNFlags(Registers[Rn] & Registers[Rm]); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/Thumb/Exception.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Breakpoint. 7 | /// 8 | private void Thumb_BKPT() 9 | { 10 | uint SPSR = Registers.CPSR; 11 | Registers.Mode = ARMMode.Abort; 12 | Registers[14] = Registers[15] - 2; 13 | Registers.SPSR = SPSR; 14 | Registers.SetFlag(ARMFlag.Thumb, false); 15 | Registers.SetFlag(ARMFlag.IRQDisable, true); 16 | Registers.SetFlag(ARMFlag.AbortDisable, true); 17 | Registers.SetFlag(ARMFlag.Endianness, false); 18 | 19 | Registers[15] = HighVectors ? 0xffff000c : 0xc; 20 | 21 | if (OnBreakpoint != null) 22 | { 23 | ushort Code = (ushort)(Opcode & 0xff); 24 | OnBreakpoint(this, new BreakpointEventArgs(Code)); 25 | } 26 | } 27 | 28 | /// 29 | /// Change Processor State. 30 | /// 31 | private void Thumb_CPS() 32 | { 33 | if (Registers.Mode != ARMMode.User) 34 | { 35 | bool Value = IsOpcodeBitSet(4); 36 | if (IsOpcodeBitSet(0)) Registers.SetFlag(ARMFlag.FIQDisable, Value); 37 | if (IsOpcodeBitSet(1)) Registers.SetFlag(ARMFlag.IRQDisable, Value); 38 | if (IsOpcodeBitSet(2)) Registers.SetFlag(ARMFlag.AbortDisable, Value); 39 | } 40 | } 41 | 42 | /// 43 | /// Software Interrupt. 44 | /// 45 | private void Thumb_SWI() 46 | { 47 | uint SPSR = Registers.CPSR; 48 | Registers.Mode = ARMMode.Supervisor; 49 | Registers[14] = Registers[15] - 2; 50 | Registers.SPSR = SPSR; 51 | Registers.SetFlag(ARMFlag.Thumb, false); 52 | Registers.SetFlag(ARMFlag.IRQDisable, true); 53 | Registers.SetFlag(ARMFlag.Endianness, false); 54 | 55 | Registers[15] = HighVectors ? 0xffff0008 : 8; 56 | 57 | if (OnSoftwareInterrupt != null) 58 | { 59 | uint Code = Opcode & 0xff; 60 | OnSoftwareInterrupt(this, new SoftwareInterruptEventArgs(Code)); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/Thumb/LoadAndStore.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | //Load 6 | 7 | /// 8 | /// Load Multiple Increment After. 9 | /// 10 | private void Thumb_LDMIA() 11 | { 12 | byte RegisterList = (byte)(Opcode & 0xff); 13 | int Rn = (int)((Opcode >> 8) & 7); 14 | 15 | uint Count = 0; 16 | for (int Index = 0; Index < 8; Index++) 17 | { 18 | if ((RegisterList & (1 << Index)) != 0) Count += 4; 19 | } 20 | 21 | uint Address = Registers[Rn]; 22 | Registers[Rn] += Count; 23 | 24 | for (int Index = 0; Index < 8; Index++) 25 | { 26 | if ((RegisterList & (1 << Index)) != 0) 27 | { 28 | Registers[Index] = ReadUInt32E(Address); 29 | Address += 4; 30 | } 31 | } 32 | } 33 | 34 | /// 35 | /// Load Register (1). 36 | /// 37 | private void Thumb_LDR() 38 | { 39 | int Rd = (int)(Opcode & 7); 40 | int Rn = (int)((Opcode >> 3) & 7); 41 | uint Immediate = (Opcode >> 6) & 0x1f; 42 | 43 | uint Address = Registers[Rn] + (Immediate << 2); 44 | Registers[Rd] = ROR(ReadUInt32E(Address & 0xfffffffc), (int)(Address & 3) << 3); 45 | } 46 | 47 | /// 48 | /// Load Register (2). 49 | /// 50 | private void Thumb_LDR_2() 51 | { 52 | int Rd = (int)(Opcode & 7); 53 | int Rn = (int)((Opcode >> 3) & 7); 54 | int Rm = (int)((Opcode >> 6) & 7); 55 | 56 | uint Address = Registers[Rn] + Registers[Rm]; 57 | Registers[Rd] = ROR(ReadUInt32E(Address & 0xfffffffc), (int)(Address & 3) << 3); 58 | } 59 | 60 | /// 61 | /// Load Register (3). 62 | /// 63 | private void Thumb_LDR_3() 64 | { 65 | uint Immediate = Opcode & 0xff; 66 | int Rd = (int)((Opcode >> 8) & 7); 67 | 68 | uint Address = (Registers[15] & 0xfffffffc) + (Immediate << 2); 69 | Registers[Rd] = ROR(ReadUInt32E(Address & 0xfffffffc), (int)(Address & 3) << 3); 70 | } 71 | 72 | /// 73 | /// Load Register (4). 74 | /// 75 | private void Thumb_LDR_4() 76 | { 77 | uint Immediate = Opcode & 0xff; 78 | int Rd = (int)((Opcode >> 8) & 7); 79 | 80 | uint Address = Registers[13] + (Immediate << 2); 81 | Registers[Rd] = ROR(ReadUInt32E(Address & 0xfffffffc), (int)(Address & 3) << 3); 82 | } 83 | 84 | /// 85 | /// Load Register Byte (1). 86 | /// 87 | private void Thumb_LDRB() 88 | { 89 | int Rd = (int)(Opcode & 7); 90 | int Rn = (int)((Opcode >> 3) & 7); 91 | uint Immediate = (Opcode >> 6) & 0x1f; 92 | 93 | uint Address = Registers[Rn] + Immediate; 94 | Registers[Rd] = Bus.ReadUInt8(Address); 95 | } 96 | 97 | /// 98 | /// Load Register Byte (2). 99 | /// 100 | private void Thumb_LDRB_2() 101 | { 102 | int Rd = (int)(Opcode & 7); 103 | int Rn = (int)((Opcode >> 3) & 7); 104 | int Rm = (int)((Opcode >> 6) & 7); 105 | 106 | uint Address = Registers[Rn] + Registers[Rm]; 107 | Registers[Rd] = Bus.ReadUInt8(Address); 108 | } 109 | 110 | /// 111 | /// Load Register Halfword (1). 112 | /// 113 | private void Thumb_LDRH() 114 | { 115 | int Rd = (int)(Opcode & 7); 116 | int Rn = (int)((Opcode >> 3) & 7); 117 | uint Immediate = (Opcode >> 6) & 0x1f; 118 | 119 | uint Address = Registers[Rn] + (Immediate << 1); 120 | Registers[Rd] = ReadUInt16E(Address); 121 | } 122 | 123 | /// 124 | /// Load Register Halfword (2). 125 | /// 126 | private void Thumb_LDRH_2() 127 | { 128 | int Rd = (int)(Opcode & 7); 129 | int Rn = (int)((Opcode >> 3) & 7); 130 | int Rm = (int)((Opcode >> 6) & 7); 131 | 132 | uint Address = Registers[Rn] + Registers[Rm]; 133 | Registers[Rd] = ReadUInt16E(Address); 134 | } 135 | 136 | /// 137 | /// Load Register Signed Byte. 138 | /// 139 | private void Thumb_LDRSB() 140 | { 141 | int Rd = (int)(Opcode & 7); 142 | int Rn = (int)((Opcode >> 3) & 7); 143 | int Rm = (int)((Opcode >> 6) & 7); 144 | 145 | uint Address = Registers[Rn] + Registers[Rm]; 146 | sbyte Value = (sbyte)Bus.ReadUInt8(Address); 147 | Registers[Rd] = (uint)Value; 148 | } 149 | 150 | /// 151 | /// Load Register Signed Halfword. 152 | /// 153 | private void Thumb_LDRSH() 154 | { 155 | int Rd = (int)(Opcode & 7); 156 | int Rn = (int)((Opcode >> 3) & 7); 157 | int Rm = (int)((Opcode >> 6) & 7); 158 | 159 | uint Address = Registers[Rn] + Registers[Rm]; 160 | short Value = (short)ReadUInt16E(Address); 161 | Registers[Rd] = (uint)Value; 162 | } 163 | 164 | /// 165 | /// Set Endian. 166 | /// 167 | private void Thumb_SETEND() 168 | { 169 | Registers.SetFlag(ARMFlag.Endianness, IsOpcodeBitSet(3)); 170 | } 171 | 172 | //Store 173 | 174 | /// 175 | /// Store Multiple Increment After. 176 | /// 177 | private void Thumb_STMIA() 178 | { 179 | byte RegisterList = (byte)(Opcode & 0xff); 180 | int Rn = (int)((Opcode >> 8) & 7); 181 | 182 | uint Count = 0; 183 | for (int Index = 0; Index < 8; Index++) 184 | { 185 | if ((RegisterList & (1 << Index)) != 0) Count++; 186 | } 187 | 188 | uint Address = Registers[Rn]; 189 | Registers[Rn] += Count << 2; 190 | 191 | for (int Index = 0; Index < 8; Index++) 192 | { 193 | if ((RegisterList & (1 << Index)) != 0) 194 | { 195 | WriteUInt32E(Address, Registers[Index]); 196 | Address += 4; 197 | } 198 | } 199 | } 200 | 201 | /// 202 | /// Store Register (1). 203 | /// 204 | private void Thumb_STR() 205 | { 206 | int Rd = (int)(Opcode & 7); 207 | int Rn = (int)((Opcode >> 3) & 7); 208 | uint Immediate = (Opcode >> 6) & 0x1f; 209 | 210 | uint Address = Registers[Rn] + (Immediate << 2); 211 | WriteUInt32(Address, Registers[Rd]); 212 | } 213 | 214 | /// 215 | /// Store Register (2). 216 | /// 217 | private void Thumb_STR_2() 218 | { 219 | int Rd = (int)(Opcode & 7); 220 | int Rn = (int)((Opcode >> 3) & 7); 221 | int Rm = (int)((Opcode >> 6) & 7); 222 | 223 | uint Address = Registers[Rn] + Registers[Rm]; 224 | WriteUInt32E(Address, Registers[Rd]); 225 | } 226 | 227 | /// 228 | /// Store Register (3). 229 | /// 230 | private void Thumb_STR_3() 231 | { 232 | uint Immediate = Opcode & 0xff; 233 | int Rd = (int)((Opcode >> 8) & 7); 234 | 235 | uint Address = Registers[13] + (Immediate << 2); 236 | WriteUInt32E(Address, Registers[Rd]); 237 | } 238 | 239 | /// 240 | /// Store Register Byte (1). 241 | /// 242 | private void Thumb_STRB() 243 | { 244 | int Rd = (int)(Opcode & 7); 245 | int Rn = (int)((Opcode >> 3) & 7); 246 | uint Immediate = (Opcode >> 6) & 0x1f; 247 | 248 | uint Address = Registers[Rn] + Immediate; 249 | Bus.WriteUInt8(Address, (byte)Registers[Rd]); 250 | } 251 | 252 | /// 253 | /// Store Register Byte (2). 254 | /// 255 | private void Thumb_STRB_2() 256 | { 257 | int Rd = (int)(Opcode & 7); 258 | int Rn = (int)((Opcode >> 3) & 7); 259 | int Rm = (int)((Opcode >> 6) & 7); 260 | 261 | uint Address = Registers[Rn] + Registers[Rm]; 262 | Bus.WriteUInt8(Address, (byte)Registers[Rd]); 263 | } 264 | 265 | /// 266 | /// Store Register Halfword (1). 267 | /// 268 | private void Thumb_STRH() 269 | { 270 | int Rd = (int)(Opcode & 7); 271 | int Rn = (int)((Opcode >> 3) & 7); 272 | uint Immediate = (Opcode >> 6) & 0x1f; 273 | 274 | uint Address = Registers[Rn] + (Immediate << 1); 275 | WriteUInt16E(Address, (ushort)Registers[Rd]); 276 | } 277 | 278 | /// 279 | /// Store Register Halfword (2). 280 | /// 281 | private void Thumb_STRH_2() 282 | { 283 | int Rd = (int)(Opcode & 7); 284 | int Rn = (int)((Opcode >> 3) & 7); 285 | int Rm = (int)((Opcode >> 6) & 7); 286 | 287 | uint Address = Registers[Rn] + Registers[Rm]; 288 | WriteUInt16E(Address, (ushort)Registers[Rd]); 289 | } 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/Thumb/Logical.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// And. 7 | /// 8 | private void Thumb_AND() 9 | { 10 | int Rd = (int)(Opcode & 7); 11 | int Rm = (int)((Opcode >> 3) & 7); 12 | 13 | Registers[Rd] &= Registers[Rm]; 14 | SetZNFlags(Registers[Rd]); 15 | } 16 | 17 | /// 18 | /// Bit Clear. 19 | /// 20 | private void Thumb_BIC() 21 | { 22 | int Rd = (int)(Opcode & 7); 23 | int Rm = (int)((Opcode >> 3) & 7); 24 | 25 | Registers[Rd] &= ~Registers[Rm]; 26 | SetZNFlags(Registers[Rd]); 27 | } 28 | 29 | /// 30 | /// Exclusive Or. 31 | /// 32 | private void Thumb_EOR() 33 | { 34 | int Rd = (int)(Opcode & 7); 35 | int Rm = (int)((Opcode >> 3) & 7); 36 | 37 | Registers[Rd] ^= Registers[Rm]; 38 | SetZNFlags(Registers[Rd]); 39 | } 40 | 41 | /// 42 | /// Logical Shift Left (1). 43 | /// 44 | private void Thumb_LSL() 45 | { 46 | int Rd = (int)(Opcode & 7); 47 | int Rm = (int)((Opcode >> 3) & 7); 48 | int Shift = (int)((Opcode >> 6) & 0x1f); 49 | 50 | if (Shift > 0) Registers.SetFlag(ARMFlag.Carry, (Registers[Rm] & (1 << (32 - Shift))) != 0); 51 | Registers[Rd] = Registers[Rm] << Shift; 52 | 53 | SetZNFlags(Registers[Rd]); 54 | } 55 | 56 | /// 57 | /// Logical Shift Left (2). 58 | /// 59 | private void Thumb_LSL_2() 60 | { 61 | int Rd = (int)(Opcode & 7); 62 | int Rs = (int)((Opcode >> 3) & 7); 63 | 64 | int Shift = (int)(Registers[Rs] & 0xff); 65 | if (Shift > 0) 66 | { 67 | bool Carry = false; 68 | if (Shift <= 32) 69 | { 70 | Carry = (Registers[Rd] & (1 << (32 - Shift))) != 0; 71 | Registers[Rd] = (uint)((ulong)Registers[Rd] << Shift); 72 | } 73 | else 74 | Registers[Rd] = 0; 75 | 76 | Registers.SetFlag(ARMFlag.Carry, Carry); 77 | } 78 | 79 | SetZNFlags(Registers[Rd]); 80 | } 81 | 82 | /// 83 | /// Logical Shift Right (1). 84 | /// 85 | private void Thumb_LSR() 86 | { 87 | int Rd = (int)(Opcode & 7); 88 | int Rm = (int)((Opcode >> 3) & 7); 89 | int Shift = (int)((Opcode >> 6) & 0x1f); 90 | 91 | if (Shift == 0) Shift = 32; 92 | Registers.SetFlag(ARMFlag.Carry, (Registers[Rm] & (1 << (Shift - 1))) != 0); 93 | Registers[Rd] = (uint)((ulong)Registers[Rm] >> Shift); 94 | 95 | SetZNFlags(Registers[Rd]); 96 | } 97 | 98 | /// 99 | /// Logical Shift Right (2). 100 | /// 101 | private void Thumb_LSR_2() 102 | { 103 | int Rd = (int)(Opcode & 7); 104 | int Rs = (int)((Opcode >> 3) & 7); 105 | 106 | int Shift = (int)(Registers[Rs] & 0xff); 107 | if (Shift > 0) 108 | { 109 | bool Carry = false; 110 | if (Shift <= 32) 111 | { 112 | Carry = (Registers[Rd] & (1 << (Shift - 1))) != 0; 113 | Registers[Rd] = (uint)((ulong)Registers[Rd] >> Shift); 114 | } 115 | else 116 | Registers[Rd] = 0; 117 | 118 | Registers.SetFlag(ARMFlag.Carry, Carry); 119 | } 120 | 121 | SetZNFlags(Registers[Rd]); 122 | } 123 | 124 | /// 125 | /// Or. 126 | /// 127 | private void Thumb_ORR() 128 | { 129 | int Rd = (int)(Opcode & 7); 130 | int Rm = (int)((Opcode >> 3) & 7); 131 | 132 | Registers[Rd] |= Registers[Rm]; 133 | SetZNFlags(Registers[Rd]); 134 | } 135 | 136 | /// 137 | /// Byte-Reverse Word. 138 | /// 139 | private void Thumb_REV() 140 | { 141 | int Rd = (int)(Opcode & 7); 142 | int Rn = (int)((Opcode >> 3) & 7); 143 | 144 | Registers[Rd] = (Registers[Rn] >> 24) | 145 | ((Registers[Rn] >> 8) & 0xff00) | 146 | ((Registers[Rn] & 0xff00) << 8) | 147 | ((Registers[Rn] & 0xff) << 24); 148 | } 149 | 150 | /// 151 | /// Byte-Reverse Packed Halfword. 152 | /// 153 | private void Thumb_REV16() 154 | { 155 | int Rd = (int)(Opcode & 7); 156 | int Rn = (int)((Opcode >> 3) & 7); 157 | 158 | Registers[Rd] = ((Registers[Rn] >> 8) & 0xff0000) | 159 | ((Registers[Rn] & 0xff0000) << 8) | 160 | ((Registers[Rn] >> 8) & 0xff) | 161 | ((Registers[Rn] & 0xff) << 8); 162 | } 163 | 164 | /// 165 | /// Byte-Reverse Signed Halfword. 166 | /// 167 | private void Thumb_REVSH() 168 | { 169 | int Rd = (int)(Opcode & 7); 170 | int Rn = (int)((Opcode >> 3) & 7); 171 | 172 | Registers[Rd] = ((Registers[Rn] >> 8) & 0xff) | ((Registers[Rn] & 0xff) << 8); 173 | if ((Registers[Rn] & 0x80) != 0) Registers[Rd] |= 0xffff0000; 174 | } 175 | 176 | /// 177 | /// Rotate Right. 178 | /// 179 | private void Thumb_ROR() 180 | { 181 | int Rd = (int)(Opcode & 7); 182 | int Rs = (int)((Opcode >> 3) & 7); 183 | 184 | int Shift = (int)(Registers[Rs] & 0xff); 185 | if (Shift > 0) 186 | { 187 | Shift &= 0x1f; 188 | if (Shift > 0) 189 | { 190 | Registers.SetFlag(ARMFlag.Carry, (Registers[Rd] & (1 << (Shift - 1))) != 0); 191 | Registers[Rd] = ROR(Registers[Rd], Shift); 192 | } 193 | else 194 | Registers.SetFlag(ARMFlag.Carry, (Registers[Rd] & 0x80000000) != 0); 195 | } 196 | 197 | SetZNFlags(Registers[Rd]); 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/ARM/Instructions/Thumb/Move.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Copy. 7 | /// 8 | private void Thumb_CPY() 9 | { 10 | int Rd = (int)(Opcode & 7); 11 | int Rm = (int)((Opcode >> 3) & 7); 12 | bool H2 = IsOpcodeBitSet(6); 13 | bool H1 = IsOpcodeBitSet(7); 14 | 15 | if (H1) Rd += 8; 16 | if (H2) Rm += 8; 17 | Registers[Rd] = Registers[Rm]; 18 | if (Rd == 15) Registers[Rd] &= 0xfffffffe; 19 | } 20 | 21 | /// 22 | /// Move (1). 23 | /// 24 | private void Thumb_MOV() 25 | { 26 | uint Immediate = Opcode & 0xff; 27 | int Rd = (int)((Opcode >> 8) & 7); 28 | 29 | Registers[Rd] = Immediate; 30 | SetZNFlags(Registers[Rd]); 31 | } 32 | 33 | /// 34 | /// Move (2). 35 | /// 36 | private void Thumb_MOV_2() 37 | { 38 | int Rd = (int)(Opcode & 7); 39 | int Rn = (int)((Opcode >> 3) & 7); 40 | 41 | Registers[Rd] = Registers[Rn]; 42 | SetZNFlags(Registers[Rd]); 43 | } 44 | 45 | /// 46 | /// Move Not. 47 | /// 48 | private void Thumb_MVN() 49 | { 50 | int Rd = (int)(Opcode & 7); 51 | int Rm = (int)((Opcode >> 3) & 7); 52 | 53 | Registers[Rd] = ~Registers[Rm]; 54 | SetZNFlags(Registers[Rd]); 55 | } 56 | 57 | /// 58 | /// Pop. 59 | /// 60 | private void Thumb_POP() 61 | { 62 | for (int Index = 0; Index < 8; Index++) 63 | { 64 | if ((Opcode & (1 << Index)) != 0) 65 | { 66 | Registers[Index] = ReadUInt32E(Registers[13]); 67 | Registers[13] += 4; 68 | } 69 | } 70 | 71 | if (IsOpcodeBitSet(8)) 72 | { 73 | uint Value = ReadUInt32E(Registers[13]); 74 | Registers[15] = Value & 0xfffffffe; 75 | Registers.SetFlag(ARMFlag.Thumb, (Value & 1) != 0); 76 | Registers[13] += 4; 77 | } 78 | } 79 | 80 | /// 81 | /// Push. 82 | /// 83 | private void Thumb_PUSH() 84 | { 85 | if (IsOpcodeBitSet(8)) 86 | { 87 | Registers[13] -= 4; 88 | WriteUInt32E(Registers[13], Registers[14]); 89 | } 90 | 91 | for (int Index = 7; Index >= 0; Index--) 92 | { 93 | if ((Opcode & (1 << Index)) != 0) 94 | { 95 | Registers[13] -= 4; 96 | WriteUInt32E(Registers[13], Registers[Index]); 97 | } 98 | } 99 | } 100 | 101 | /// 102 | /// Signed Extend Byte. 103 | /// 104 | private void Thumb_SXTB() 105 | { 106 | int Rd = (int)(Opcode & 7); 107 | int Rm = (int)((Opcode >> 3) & 7); 108 | 109 | sbyte RmValue = (sbyte)Registers[Rm]; 110 | Registers[Rd] = (uint)RmValue; 111 | } 112 | 113 | /// 114 | /// Signed Extend Halfword. 115 | /// 116 | private void Thumb_SXTH() 117 | { 118 | int Rd = (int)(Opcode & 7); 119 | int Rm = (int)((Opcode >> 3) & 7); 120 | 121 | short RmValue = (short)Registers[Rm]; 122 | Registers[Rd] = (uint)RmValue; 123 | } 124 | 125 | /// 126 | /// Unsigned Extend Byte. 127 | /// 128 | private void Thumb_UXTB() 129 | { 130 | int Rd = (int)(Opcode & 7); 131 | int Rm = (int)((Opcode >> 3) & 7); 132 | 133 | Registers[Rd] = Registers[Rm] & 0xff; 134 | } 135 | 136 | /// 137 | /// Unsigned Extend Halfword. 138 | /// 139 | private void Thumb_UXTH() 140 | { 141 | int Rd = (int)(Opcode & 7); 142 | int Rm = (int)((Opcode >> 3) & 7); 143 | 144 | Registers[Rd] = Registers[Rm] & 0xffff; 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/Bus.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | /// 4 | /// ARM Bus interface for Memory access. 5 | /// 6 | public interface IBus 7 | { 8 | /// 9 | /// Reads a 8-bits value from the Memory. 10 | /// 11 | /// Address to read the data from 12 | /// Data on the address 13 | byte ReadUInt8(uint Address); 14 | 15 | /// 16 | /// Writes a 8-bits value to the Memory. 17 | /// 18 | /// Address to write the data on 19 | /// Value to be written 20 | void WriteUInt8(uint Address, byte Value); 21 | } 22 | 23 | public partial class ARMCore 24 | { 25 | //Read 26 | 27 | /// 28 | /// Reads a 16-bits Little Endian value from the Memory. 29 | /// 30 | /// Address to read the data from 31 | /// Data on the address 32 | private ushort ReadUInt16(uint Address) 33 | { 34 | return (ushort)(Bus.ReadUInt8(Address) | 35 | (Bus.ReadUInt8(Address + 1) << 8)); 36 | } 37 | 38 | /// 39 | /// Reads a 32-bits Little Endian value from the Memory. 40 | /// 41 | /// Address to read the data from 42 | /// Data on the address 43 | private uint ReadUInt32(uint Address) 44 | { 45 | return (uint)(Bus.ReadUInt8(Address) | 46 | (Bus.ReadUInt8(Address + 1) << 8) | 47 | (Bus.ReadUInt8(Address + 2) << 16) | 48 | (Bus.ReadUInt8(Address + 3) << 24)); 49 | } 50 | 51 | /// 52 | /// Reads a 16-bits value from the Memory on Little or Big Endian, depending on the E-bit setting. 53 | /// 54 | /// Address to read the data from 55 | /// Data on the address 56 | private ushort ReadUInt16E(uint Address) 57 | { 58 | if (Registers.IsFlagSet(ARMFlag.Endianness)) 59 | return (ushort)((Bus.ReadUInt8(Address) << 8) | 60 | Bus.ReadUInt8(Address + 1)); 61 | else 62 | return ReadUInt16(Address); 63 | } 64 | 65 | /// 66 | /// Reads a 32-bits value from the Memory on Little or Big Endian, depending on the E-bit setting. 67 | /// 68 | /// Address to read the data from 69 | /// Data on the address 70 | private uint ReadUInt32E(uint Address) 71 | { 72 | if (Registers.IsFlagSet(ARMFlag.Endianness)) 73 | return (uint)((Bus.ReadUInt8(Address) << 24) | 74 | (Bus.ReadUInt8(Address + 1) << 16) | 75 | (Bus.ReadUInt8(Address + 2) << 8) | 76 | Bus.ReadUInt8(Address + 3)); 77 | else 78 | return ReadUInt32(Address); 79 | } 80 | 81 | //Write 82 | 83 | /// 84 | /// Writes a 16-bits Little Endian value to the Memory. 85 | /// 86 | /// Address to write the data on 87 | /// Value to be written 88 | private void WriteUInt16(uint Address, ushort Value) 89 | { 90 | Bus.WriteUInt8(Address, (byte)Value); 91 | Bus.WriteUInt8(Address + 1, (byte)(Value >> 8)); 92 | } 93 | 94 | /// 95 | /// Writes a 32-bits Little Endian value to the Memory. 96 | /// 97 | /// Address to write the data on 98 | /// Value to be written 99 | public void WriteUInt32(uint Address, uint Value) 100 | { 101 | Bus.WriteUInt8(Address, (byte)Value); 102 | Bus.WriteUInt8(Address + 1, (byte)(Value >> 8)); 103 | Bus.WriteUInt8(Address + 2, (byte)(Value >> 16)); 104 | Bus.WriteUInt8(Address + 3, (byte)(Value >> 24)); 105 | } 106 | 107 | /// 108 | /// Writes a 16-bits value to the Memory on Little or Big Endian, depending on the E-bit setting. 109 | /// 110 | /// Address to write the data on 111 | /// Value to be written 112 | private void WriteUInt16E(uint Address, ushort Value) 113 | { 114 | if (Registers.IsFlagSet(ARMFlag.Endianness)) 115 | { 116 | Bus.WriteUInt8(Address, (byte)(Value >> 8)); 117 | Bus.WriteUInt8(Address + 1, (byte)Value); 118 | } 119 | else 120 | WriteUInt16(Address, Value); 121 | } 122 | 123 | /// 124 | /// Writes a 32-bits value to the Memory on Little or Big Endian, depending on the E-bit setting. 125 | /// 126 | /// Address to write the data on 127 | /// Value to be written 128 | private void WriteUInt32E(uint Address, uint Value) 129 | { 130 | if (Registers.IsFlagSet(ARMFlag.Endianness)) 131 | { 132 | Bus.WriteUInt8(Address, (byte)(Value >> 24)); 133 | Bus.WriteUInt8(Address + 1, (byte)(Value >> 16)); 134 | Bus.WriteUInt8(Address + 2, (byte)(Value >> 8)); 135 | Bus.WriteUInt8(Address + 3, (byte)Value); 136 | } 137 | else 138 | WriteUInt32(Address, Value); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/Condition.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// ARM CPU conditions. 7 | /// 8 | private enum ARMCondition 9 | { 10 | Equal = 0, 11 | NotEqual = 1, 12 | CarrySet = 2, 13 | CarryClear = 3, 14 | Minus = 4, 15 | Plus = 5, 16 | Overflow = 6, 17 | NoOverflow = 7, 18 | UnsignedHigher = 8, 19 | UnsignedLowerOrSame = 9, 20 | SignedGreaterThanOrEqual = 0xa, 21 | SignedLessThan = 0xb, 22 | SignedGreaterThan = 0xc, 23 | SignedLessThanOrEqual = 0xd, 24 | Always = 0xe, 25 | Unconditional = 0xf 26 | } 27 | 28 | /// 29 | /// Checks whenever the Condition of a Opcode matches the current Status Register, to see if the condition is true. 30 | /// 31 | /// The Condition of the Opcode 32 | /// If the condition is true or not 33 | private bool IsConditionMet(ARMCondition Condition) 34 | { 35 | switch (Condition) 36 | { 37 | case ARMCondition.Equal: return Registers.IsFlagSet(ARMFlag.Zero); 38 | case ARMCondition.NotEqual: return Registers.IsFlagClear(ARMFlag.Zero); 39 | case ARMCondition.CarrySet: return Registers.IsFlagSet(ARMFlag.Carry); 40 | case ARMCondition.CarryClear: return Registers.IsFlagClear(ARMFlag.Carry); 41 | case ARMCondition.Minus: return Registers.IsFlagSet(ARMFlag.Negative); 42 | case ARMCondition.Plus: return Registers.IsFlagClear(ARMFlag.Negative); 43 | case ARMCondition.Overflow: return Registers.IsFlagSet(ARMFlag.Overflow); 44 | case ARMCondition.NoOverflow: return Registers.IsFlagClear(ARMFlag.Overflow); 45 | case ARMCondition.UnsignedHigher: return ConditionHI(); 46 | case ARMCondition.UnsignedLowerOrSame: return ConditionLS(); 47 | case ARMCondition.SignedGreaterThanOrEqual: return ConditionGE(); 48 | case ARMCondition.SignedLessThan: return ConditionLT(); 49 | case ARMCondition.SignedGreaterThan: return Registers.IsFlagClear(ARMFlag.Zero) && ConditionGE(); 50 | case ARMCondition.SignedLessThanOrEqual: return Registers.IsFlagSet(ARMFlag.Zero) || ConditionLT(); 51 | case ARMCondition.Always: return true; 52 | } 53 | 54 | return false; 55 | } 56 | 57 | /// 58 | /// Checks if the Unsigned Higher condition is met, based on the values of the Status register. 59 | /// 60 | /// True if the condition is met, false otherwise 61 | private bool ConditionHI() 62 | { 63 | return Registers.IsFlagSet(ARMFlag.Carry) && Registers.IsFlagClear(ARMFlag.Zero); 64 | } 65 | 66 | /// 67 | /// Checks if the Unsigned Lower or Same condition is met, based on the values of the Status register. 68 | /// 69 | /// True if the condition is met, false otherwise 70 | private bool ConditionLS() 71 | { 72 | return Registers.IsFlagClear(ARMFlag.Carry) || Registers.IsFlagSet(ARMFlag.Zero); 73 | } 74 | 75 | /// 76 | /// Checks if the Greater Than or Equal condition is met, based on the values of the Status register. 77 | /// 78 | /// True if the condition is met, false otherwise 79 | private bool ConditionGE() 80 | { 81 | return Registers.IsFlagSet(ARMFlag.Negative) == Registers.IsFlagSet(ARMFlag.Overflow); 82 | } 83 | 84 | /// 85 | /// Checks if the Less Than condition is met, based on the values of the Status register. 86 | /// 87 | /// True if the condition is met, false otherwise 88 | private bool ConditionLT() 89 | { 90 | return Registers.IsFlagSet(ARMFlag.Negative) != Registers.IsFlagSet(ARMFlag.Overflow); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/Coprocessor15.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | class Coprocessor15 4 | { 5 | //ARM1176 CP15 setup 6 | 7 | private const uint CP15_MainId = 0x410FB767; 8 | private const uint CP15_CacheType = 0x10152152; 9 | private const uint CP15_TCMStatus = 0x20002; 10 | private const uint CP15_TLBType = 0x800; 11 | 12 | private const uint CP15_ProcessorFeature0 = 0x111; 13 | private const uint CP15_ProcessorFeature1 = 0x11; 14 | private const uint CP15_DebugFeature0 = 0x33; 15 | private const uint CP15_AuxiliaryFeature0 = 0; 16 | private const uint CP15_MemoryModelFeature0 = 0x1130003; 17 | private const uint CP15_MemoryModelFeature1 = 0x10030302; 18 | private const uint CP15_MemoryModelFeature2 = 0x1222100; 19 | private const uint CP15_MemoryModelFeature3 = 0; 20 | 21 | private const uint CP15_InstructionSetFeatureAttribute0 = 0x140011; 22 | private const uint CP15_InstructionSetFeatureAttribute1 = 0x12002111; 23 | private const uint CP15_InstructionSetFeatureAttribute2 = 0x11231121; 24 | private const uint CP15_InstructionSetFeatureAttribute3 = 0x1102131; 25 | private const uint CP15_InstructionSetFeatureAttribute4 = 0x1141; 26 | private const uint CP15_InstructionSetFeatureAttribute5 = 0; 27 | 28 | private uint CP15_Control; 29 | private uint CP15_AuxiliaryControl; 30 | private uint CP15_CoprocessorAccessControl; 31 | 32 | /// 33 | /// Reads a value from the "CP15" Coprocessor. 34 | /// 35 | /// The CRn register index 36 | /// The Opcode 1 value 37 | /// The CRm register index 38 | /// The Opcode 2 value 39 | /// The value at the given register 40 | public uint Read(int CRn, uint Op1, int CRm, uint Op2) 41 | { 42 | if (Op1 == 0) 43 | { 44 | switch (CRn) 45 | { 46 | case 0: 47 | switch (CRm) 48 | { 49 | case 0: 50 | switch (Op2) 51 | { 52 | case 0: return CP15_MainId; 53 | case 1: return CP15_CacheType; 54 | case 2: return CP15_TCMStatus; 55 | case 3: return CP15_TLBType; 56 | } 57 | break; 58 | case 1: 59 | switch (Op2) 60 | { 61 | case 0: return CP15_ProcessorFeature0; 62 | case 1: return CP15_ProcessorFeature1; 63 | case 2: return CP15_DebugFeature0; 64 | case 3: return CP15_AuxiliaryFeature0; 65 | case 4: return CP15_MemoryModelFeature0; 66 | case 5: return CP15_MemoryModelFeature1; 67 | case 6: return CP15_MemoryModelFeature2; 68 | case 7: return CP15_MemoryModelFeature3; 69 | } 70 | break; 71 | case 2: 72 | switch (Op2) 73 | { 74 | case 0: return CP15_InstructionSetFeatureAttribute0; 75 | case 1: return CP15_InstructionSetFeatureAttribute1; 76 | case 2: return CP15_InstructionSetFeatureAttribute2; 77 | case 3: return CP15_InstructionSetFeatureAttribute3; 78 | case 4: return CP15_InstructionSetFeatureAttribute4; 79 | case 5: return CP15_InstructionSetFeatureAttribute5; 80 | } 81 | break; 82 | } 83 | break; 84 | case 2: 85 | switch (CRm) 86 | { 87 | case 0: 88 | switch (Op2) 89 | { 90 | case 0: return CP15_Control; 91 | case 1: return CP15_AuxiliaryControl; 92 | case 2: return CP15_CoprocessorAccessControl; 93 | } 94 | break; 95 | } 96 | break; 97 | } 98 | } 99 | 100 | return 0; 101 | } 102 | 103 | /// 104 | /// Writes a value to the "CP15" Coprocessor. 105 | /// 106 | /// The CRn register index 107 | /// The Opcode 1 value 108 | /// The CRm register index 109 | /// The Opcode 2 value 110 | /// Value to be written 111 | public void Write(int CRn, uint Op1, int CRm, uint Op2, uint Value) 112 | { 113 | if (Op1 == 0) 114 | { 115 | switch (CRn) 116 | { 117 | case 2: 118 | switch (CRm) 119 | { 120 | case 0: 121 | switch (Op2) 122 | { 123 | case 0: CP15_Control = Value; break; 124 | case 1: CP15_AuxiliaryControl = Value; break; 125 | case 2: CP15_CoprocessorAccessControl = Value; break; 126 | } 127 | break; 128 | } 129 | break; 130 | } 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/Registers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SharpARM.ARM11 4 | { 5 | public partial class ARMCore 6 | { 7 | /// 8 | /// Flags used on the registers CPSR and SPSR. 9 | /// 10 | public enum ARMFlag : uint 11 | { 12 | Thumb = 0x20, //T 13 | FIQDisable = 0x40, //F 14 | IRQDisable = 0x80, //I 15 | AbortDisable = 0x100, //A 16 | Endianness = 0x200, //E 17 | Saturation = 0x8000000, //Q 18 | Overflow = 0x10000000, //V 19 | Carry = 0x20000000, //C 20 | Zero = 0x40000000, //Z 21 | Negative = 0x80000000 //N 22 | } 23 | 24 | /// 25 | /// ARM CPU executions modes. 26 | /// 27 | public enum ARMMode 28 | { 29 | User = 0x10, 30 | FIQ = 0x11, 31 | IRQ = 0X12, 32 | Supervisor = 0x13, 33 | Abort = 0x17, 34 | Undefined = 0x1b, 35 | System = 0x1f 36 | } 37 | 38 | /// 39 | /// Represents all the 37 ARM Registers. 40 | /// 41 | public class ARMRegisters 42 | { 43 | /* 44 | * General purpose registers 45 | * R13 = Stack pointer 46 | * R14 = Link register 47 | * R15 = Program counter 48 | */ 49 | private uint[] R = new uint[16]; 50 | 51 | private uint R8_FIQ; 52 | private uint R9_FIQ; 53 | private uint R10_FIQ; 54 | private uint R11_FIQ; 55 | private uint R12_FIQ; 56 | private uint R13_FIQ; 57 | private uint R14_FIQ; 58 | 59 | private uint R13_IRQ; 60 | private uint R14_IRQ; 61 | 62 | private uint R13_SVC; 63 | private uint R14_SVC; 64 | 65 | private uint R13_ABT; 66 | private uint R14_ABT; 67 | 68 | private uint R13_UNDEF; 69 | private uint R14_UNDEF; 70 | 71 | /* 72 | * Status registers 73 | */ 74 | 75 | /// 76 | /// Current Processor Status Register. 77 | /// 78 | public uint CPSR; 79 | private uint SPSR_FIQ; 80 | private uint SPSR_IRQ; 81 | private uint SPSR_SVC; 82 | private uint SPSR_ABT; 83 | private uint SPSR_UNDEF; 84 | 85 | /// 86 | /// This flag is set to true every time the value of R15 is changed. 87 | /// It needs to be set to false manually. Useful for handling the 3-stage pipeline. 88 | /// 89 | public bool PCChanged; 90 | 91 | /// 92 | /// Gets or sets the value of the SPSR register of the current mode. 93 | /// 94 | public uint SPSR 95 | { 96 | get 97 | { 98 | switch (Mode) 99 | { 100 | case ARMMode.FIQ: return SPSR_FIQ; 101 | case ARMMode.IRQ: return SPSR_IRQ; 102 | case ARMMode.Supervisor: return SPSR_SVC; 103 | case ARMMode.Abort: return SPSR_ABT; 104 | case ARMMode.Undefined: return SPSR_UNDEF; 105 | } 106 | 107 | return 0; 108 | } 109 | set 110 | { 111 | switch (Mode) 112 | { 113 | case ARMMode.FIQ: SPSR_FIQ = value; break; 114 | case ARMMode.IRQ: SPSR_IRQ = value; break; 115 | case ARMMode.Supervisor: SPSR_SVC = value; break; 116 | case ARMMode.Abort: SPSR_ABT = value; break; 117 | case ARMMode.Undefined: SPSR_UNDEF = value; break; 118 | } 119 | } 120 | } 121 | 122 | /// 123 | /// Gets or sets the current CPU execution mode. 124 | /// 125 | public ARMMode Mode 126 | { 127 | get 128 | { 129 | return (ARMMode)(CPSR & 0x1f); 130 | } 131 | set 132 | { 133 | CPSR = (uint)(CPSR & ~0x1f) | (uint)value; 134 | } 135 | } 136 | 137 | 138 | /// 139 | /// Gets or sets the Greater than or Equal bits on the CPSR Register. 140 | /// 141 | public byte GE 142 | { 143 | get 144 | { 145 | return (byte)((CPSR >> 16) & 0xf); 146 | } 147 | set 148 | { 149 | CPSR = (CPSR & 0xfff0ffff) | (uint)(value << 16); 150 | } 151 | } 152 | 153 | /// 154 | /// ARM General purpose registers, accessible by Index number. 155 | /// 156 | /// The Index number of the Register to work with 157 | /// The value of the Register with the specified Index 158 | public uint this[int RegisterIndex] 159 | { 160 | get 161 | { 162 | switch (Mode) 163 | { 164 | case ARMMode.User: 165 | case ARMMode.System: 166 | return R[RegisterIndex]; 167 | 168 | case ARMMode.FIQ: 169 | if (RegisterIndex < 8 || RegisterIndex == 15) 170 | return R[RegisterIndex]; 171 | else 172 | { 173 | switch (RegisterIndex) 174 | { 175 | case 8: return R8_FIQ; 176 | case 9: return R9_FIQ; 177 | case 10: return R10_FIQ; 178 | case 11: return R11_FIQ; 179 | case 12: return R12_FIQ; 180 | case 13: return R13_FIQ; 181 | case 14: return R14_FIQ; 182 | } 183 | } 184 | break; 185 | 186 | case ARMMode.IRQ: 187 | if (RegisterIndex < 13 || RegisterIndex == 15) 188 | return R[RegisterIndex]; 189 | else 190 | { 191 | switch (RegisterIndex) 192 | { 193 | case 13: return R13_IRQ; 194 | case 14: return R14_IRQ; 195 | } 196 | } 197 | break; 198 | 199 | case ARMMode.Supervisor: 200 | if (RegisterIndex < 13 || RegisterIndex == 15) 201 | return R[RegisterIndex]; 202 | else 203 | { 204 | switch (RegisterIndex) 205 | { 206 | case 13: return R13_SVC; 207 | case 14: return R14_SVC; 208 | } 209 | } 210 | break; 211 | 212 | case ARMMode.Abort: 213 | if (RegisterIndex < 13 || RegisterIndex == 15) 214 | return R[RegisterIndex]; 215 | else 216 | { 217 | switch (RegisterIndex) 218 | { 219 | case 13: return R13_ABT; 220 | case 14: return R14_ABT; 221 | } 222 | } 223 | break; 224 | 225 | case ARMMode.Undefined: 226 | if (RegisterIndex < 13 || RegisterIndex == 15) 227 | return R[RegisterIndex]; 228 | else 229 | { 230 | switch (RegisterIndex) 231 | { 232 | case 13: return R13_UNDEF; 233 | case 14: return R14_UNDEF; 234 | } 235 | } 236 | break; 237 | 238 | default: throw new Exception("SharpARM: Invalid CPSR ARM execution Mode!"); 239 | } 240 | 241 | return 0; 242 | } 243 | set 244 | { 245 | switch (Mode) 246 | { 247 | case ARMMode.User: 248 | case ARMMode.System: 249 | R[RegisterIndex] = value; 250 | break; 251 | 252 | case ARMMode.FIQ: 253 | if (RegisterIndex < 8 || RegisterIndex == 15) 254 | R[RegisterIndex] = value; 255 | else 256 | { 257 | switch (RegisterIndex) 258 | { 259 | case 8: R8_FIQ = value; break; 260 | case 9: R9_FIQ = value; break; 261 | case 10: R10_FIQ = value; break; 262 | case 11: R11_FIQ = value; break; 263 | case 12: R12_FIQ = value; break; 264 | case 13: R13_FIQ = value; break; 265 | case 14: R14_FIQ = value; break; 266 | } 267 | } 268 | break; 269 | 270 | case ARMMode.IRQ: 271 | if (RegisterIndex < 13 || RegisterIndex == 15) 272 | R[RegisterIndex] = value; 273 | else 274 | { 275 | switch (RegisterIndex) 276 | { 277 | case 13: R13_IRQ = value; break; 278 | case 14: R14_IRQ = value; break; 279 | } 280 | } 281 | break; 282 | 283 | case ARMMode.Supervisor: 284 | if (RegisterIndex < 13 || RegisterIndex == 15) 285 | R[RegisterIndex] = value; 286 | else 287 | { 288 | switch (RegisterIndex) 289 | { 290 | case 13: R13_SVC = value; break; 291 | case 14: R14_SVC = value; break; 292 | } 293 | } 294 | break; 295 | 296 | case ARMMode.Abort: 297 | if (RegisterIndex < 13 || RegisterIndex == 15) 298 | R[RegisterIndex] = value; 299 | else 300 | { 301 | switch (RegisterIndex) 302 | { 303 | case 13: R13_ABT = value; break; 304 | case 14: R14_ABT = value; break; 305 | } 306 | } 307 | break; 308 | 309 | case ARMMode.Undefined: 310 | if (RegisterIndex < 13 || RegisterIndex == 15) 311 | R[RegisterIndex] = value; 312 | else 313 | { 314 | switch (RegisterIndex) 315 | { 316 | case 13: R13_UNDEF = value; break; 317 | case 14: R14_UNDEF = value; break; 318 | } 319 | } 320 | break; 321 | 322 | default: throw new Exception("SharpARM: Invalid CPSR ARM execution Mode!"); 323 | } 324 | 325 | if (RegisterIndex == 15) PCChanged = true; 326 | } 327 | } 328 | 329 | /// 330 | /// Checks if a Flag is set on the Status register. 331 | /// 332 | /// Flag that should be checked 333 | /// True if the flag is set, false otherwise 334 | public bool IsFlagSet(ARMFlag Flag) 335 | { 336 | return (CPSR & (uint)Flag) != 0; 337 | } 338 | 339 | /// 340 | /// Check if a Flag is cleared on the Status register. 341 | /// 342 | /// Flag that should be checked 343 | /// True if the flag is cleared, false otherwise 344 | public bool IsFlagClear(ARMFlag Flag) 345 | { 346 | return (CPSR & (uint)Flag) == 0; 347 | } 348 | 349 | /// 350 | /// Set the value of a given ARM Flag. 351 | /// 352 | /// The affected Flag 353 | /// The bit value that should be set (True = Set or False = Cleared) 354 | public void SetFlag(ARMFlag Flag, bool Value) 355 | { 356 | if (Value) CPSR |= (uint)Flag; else CPSR &= ~(uint)Flag; 357 | } 358 | } 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /ChocolateARM/ARM11/Utils.cs: -------------------------------------------------------------------------------- 1 | namespace SharpARM.ARM11 2 | { 3 | public partial class ARMCore 4 | { 5 | /// 6 | /// Checks whenever a bit on the 32-bits Opcode value is set or not. 7 | /// 8 | /// The bit that should be tested 9 | /// True if the bit is set, false otherwise 10 | private bool IsOpcodeBitSet(int Bit) 11 | { 12 | return (Opcode & (1 << Bit)) != 0; 13 | } 14 | 15 | /// 16 | /// Shift the bits to the right, and make the exceeding bits fill the other way around. 17 | /// Example: For a 8 bits value, ROR(0b00000011, 1) = 0b10000001. 18 | /// 19 | /// Value that should be shifted 20 | /// Number of bits to shift 21 | /// The shifted value 22 | private uint ROR(uint Value, int Shift) 23 | { 24 | return (Value >> Shift) | (Value << (32 - Shift)); 25 | } 26 | 27 | /// 28 | /// Sets the Zero flag if the value is zero, and clear it otherwise. 29 | /// Sets the Negative flag if the value is negative (most heavy bit set), and clear it otherwise. 30 | /// 31 | /// The resulting 32-bits value that should be tested 32 | private void SetZNFlags(uint Value) 33 | { 34 | Registers.SetFlag(ARMFlag.Zero, Value == 0); 35 | Registers.SetFlag(ARMFlag.Negative, (Value & 0x80000000) != 0); 36 | } 37 | 38 | /// 39 | /// Sign extends a 11-bits value to a signed 32-bits value. 40 | /// 41 | /// The 11-bits value that should be extended 42 | /// The value extended into 32-bits 43 | private int SignExtend11(uint Value) 44 | { 45 | if ((Value & 0x400) != 0) 46 | return (int)(Value | 0xfffff800); 47 | else 48 | return (int)Value; 49 | } 50 | 51 | /// 52 | /// Sign extends a 12-bits value to a signed 32-bits value. 53 | /// 54 | /// The 12-bits value that should be extended 55 | /// The value extended into 32-bits 56 | private int SignExtend12(uint Value) 57 | { 58 | if ((Value & 0x800) != 0) 59 | return (int)(Value | 0xfffff000); 60 | else 61 | return (int)Value; 62 | } 63 | 64 | /// 65 | /// Sign extends a 24-bits value to a signed 32-bits value. 66 | /// 67 | /// The 24-bits value that should be extended 68 | /// The value extended into 32-bits 69 | private int SignExtend24(uint Value) 70 | { 71 | if ((Value & 0x800000) != 0) 72 | return (int)(Value | 0xff000000); 73 | else 74 | return (int)Value; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ChocolateARM/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ChocolateARM/ChocolateARM.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {47232F73-385B-43D6-8751-10B289DAEBE1} 8 | WinExe 9 | Properties 10 | ChocolateARM 11 | ChocolateARM 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | x64 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Form 80 | 81 | 82 | FrmMain.cs 83 | 84 | 85 | Form 86 | 87 | 88 | FrmUARTOutput.cs 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | FrmMain.cs 102 | 103 | 104 | FrmUARTOutput.cs 105 | 106 | 107 | ResXFileCodeGenerator 108 | Resources.Designer.cs 109 | Designer 110 | 111 | 112 | True 113 | Resources.resx 114 | 115 | 116 | SettingsSingleFileGenerator 117 | Settings.Designer.cs 118 | 119 | 120 | True 121 | Settings.settings 122 | True 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 137 | -------------------------------------------------------------------------------- /ChocolateARM/FrmMain.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ChocolateARM 2 | { 3 | partial class FrmMain 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.Screen = new System.Windows.Forms.PictureBox(); 33 | this.MenuBar = new System.Windows.Forms.MenuStrip(); 34 | this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 35 | this.MnuLoadKernelImage = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.MnuTools = new System.Windows.Forms.ToolStripMenuItem(); 37 | this.MnuDumpSDRAM = new System.Windows.Forms.ToolStripMenuItem(); 38 | this.MnuShowUART = new System.Windows.Forms.ToolStripMenuItem(); 39 | this.StatusBar = new System.Windows.Forms.StatusStrip(); 40 | this.ScreenRefresh = new System.Windows.Forms.Timer(this.components); 41 | this.MnuARMDbg = new System.Windows.Forms.ToolStripMenuItem(); 42 | ((System.ComponentModel.ISupportInitialize)(this.Screen)).BeginInit(); 43 | this.MenuBar.SuspendLayout(); 44 | this.SuspendLayout(); 45 | // 46 | // Screen 47 | // 48 | this.Screen.BackColor = System.Drawing.Color.Black; 49 | this.Screen.Location = new System.Drawing.Point(0, 24); 50 | this.Screen.Name = "Screen"; 51 | this.Screen.Size = new System.Drawing.Size(640, 480); 52 | this.Screen.TabIndex = 2; 53 | this.Screen.TabStop = false; 54 | // 55 | // MenuBar 56 | // 57 | this.MenuBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 58 | this.fileToolStripMenuItem, 59 | this.MnuTools}); 60 | this.MenuBar.Location = new System.Drawing.Point(0, 0); 61 | this.MenuBar.Name = "MenuBar"; 62 | this.MenuBar.Size = new System.Drawing.Size(640, 24); 63 | this.MenuBar.TabIndex = 3; 64 | this.MenuBar.Text = "menuStrip1"; 65 | // 66 | // fileToolStripMenuItem 67 | // 68 | this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 69 | this.MnuLoadKernelImage}); 70 | this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; 71 | this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); 72 | this.fileToolStripMenuItem.Text = "&File"; 73 | // 74 | // MnuLoadKernelImage 75 | // 76 | this.MnuLoadKernelImage.Name = "MnuLoadKernelImage"; 77 | this.MnuLoadKernelImage.Size = new System.Drawing.Size(172, 22); 78 | this.MnuLoadKernelImage.Text = "&Load Kernel image"; 79 | this.MnuLoadKernelImage.Click += new System.EventHandler(this.MnuLoadKernelImage_Click); 80 | // 81 | // MnuTools 82 | // 83 | this.MnuTools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 84 | this.MnuDumpSDRAM, 85 | this.MnuShowUART, 86 | this.MnuARMDbg}); 87 | this.MnuTools.Name = "MnuTools"; 88 | this.MnuTools.Size = new System.Drawing.Size(47, 20); 89 | this.MnuTools.Text = "&Tools"; 90 | // 91 | // MnuDumpSDRAM 92 | // 93 | this.MnuDumpSDRAM.Name = "MnuDumpSDRAM"; 94 | this.MnuDumpSDRAM.Size = new System.Drawing.Size(152, 22); 95 | this.MnuDumpSDRAM.Text = "&Dump SDRAM"; 96 | this.MnuDumpSDRAM.Click += new System.EventHandler(this.MnuDumpSDRAM_Click); 97 | // 98 | // MnuShowUART 99 | // 100 | this.MnuShowUART.Name = "MnuShowUART"; 101 | this.MnuShowUART.Size = new System.Drawing.Size(152, 22); 102 | this.MnuShowUART.Text = "&UART output"; 103 | this.MnuShowUART.Click += new System.EventHandler(this.MnuShowUART_Click); 104 | // 105 | // StatusBar 106 | // 107 | this.StatusBar.Location = new System.Drawing.Point(0, 504); 108 | this.StatusBar.Name = "StatusBar"; 109 | this.StatusBar.Size = new System.Drawing.Size(640, 22); 110 | this.StatusBar.TabIndex = 4; 111 | this.StatusBar.Text = "statusStrip1"; 112 | // 113 | // ScreenRefresh 114 | // 115 | this.ScreenRefresh.Interval = 16; 116 | this.ScreenRefresh.Tick += new System.EventHandler(this.ScreenRefresh_Tick); 117 | // 118 | // MnuARMDbg 119 | // 120 | this.MnuARMDbg.Name = "MnuARMDbg"; 121 | this.MnuARMDbg.Size = new System.Drawing.Size(152, 22); 122 | this.MnuARMDbg.Text = "&ARM Debug"; 123 | this.MnuARMDbg.Click += new System.EventHandler(this.MnuARMDbg_Click); 124 | // 125 | // FrmMain 126 | // 127 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 128 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 129 | this.ClientSize = new System.Drawing.Size(640, 526); 130 | this.Controls.Add(this.StatusBar); 131 | this.Controls.Add(this.Screen); 132 | this.Controls.Add(this.MenuBar); 133 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 134 | this.MainMenuStrip = this.MenuBar; 135 | this.MaximizeBox = false; 136 | this.Name = "FrmMain"; 137 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 138 | this.Text = "ChocolatePi Alpha"; 139 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FrmMain_FormClosing); 140 | this.Load += new System.EventHandler(this.FrmMain_Load); 141 | ((System.ComponentModel.ISupportInitialize)(this.Screen)).EndInit(); 142 | this.MenuBar.ResumeLayout(false); 143 | this.MenuBar.PerformLayout(); 144 | this.ResumeLayout(false); 145 | this.PerformLayout(); 146 | 147 | } 148 | 149 | #endregion 150 | 151 | private System.Windows.Forms.PictureBox Screen; 152 | private System.Windows.Forms.MenuStrip MenuBar; 153 | private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; 154 | private System.Windows.Forms.ToolStripMenuItem MnuLoadKernelImage; 155 | private System.Windows.Forms.StatusStrip StatusBar; 156 | private System.Windows.Forms.ToolStripMenuItem MnuTools; 157 | private System.Windows.Forms.ToolStripMenuItem MnuDumpSDRAM; 158 | private System.Windows.Forms.Timer ScreenRefresh; 159 | private System.Windows.Forms.ToolStripMenuItem MnuShowUART; 160 | private System.Windows.Forms.ToolStripMenuItem MnuARMDbg; 161 | } 162 | } 163 | 164 | -------------------------------------------------------------------------------- /ChocolateARM/FrmMain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.IO; 4 | using System.Windows.Forms; 5 | 6 | using ChocolateARM.RPi; 7 | 8 | namespace ChocolateARM 9 | { 10 | public partial class FrmMain : Form 11 | { 12 | RPiCore RaspberryPi; 13 | 14 | public FrmMain() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | private int ScreenDifferenceWidth; 20 | private int ScreenDifferenceHeight; 21 | 22 | private void FrmMain_Load(object sender, EventArgs e) 23 | { 24 | ScreenDifferenceWidth = Width - Screen.Width; 25 | ScreenDifferenceHeight = Height - Screen.Height; 26 | 27 | RaspberryPi = new RPiCore(); 28 | RaspberryPi.Memory.Video.OnScreenSetup += ScreenSetupCallback; 29 | SetupScreen = new ScreenSetupDelegate(ScreenSetup); 30 | 31 | Show(); 32 | } 33 | 34 | private void FrmMain_FormClosing(object sender, FormClosingEventArgs e) 35 | { 36 | RaspberryPi.Stop(); 37 | } 38 | 39 | private void ScreenSetupCallback() 40 | { 41 | BeginInvoke(SetupScreen); 42 | } 43 | 44 | private ScreenSetupDelegate SetupScreen; 45 | private delegate void ScreenSetupDelegate(); 46 | 47 | private void ScreenSetup() 48 | { 49 | Screen.Width = (int)RaspberryPi.Memory.Video.ScreenVirtualWidth; 50 | Screen.Height = (int)RaspberryPi.Memory.Video.ScreenVirtualHeight; 51 | Width = Screen.Width + ScreenDifferenceWidth; 52 | Height = Screen.Height + ScreenDifferenceHeight; 53 | CenterToScreen(); 54 | ScreenRefresh.Enabled = true; 55 | } 56 | 57 | private void MnuLoadKernelImage_Click(object sender, EventArgs e) 58 | { 59 | using (OpenFileDialog OpenDialog = new OpenFileDialog()) 60 | { 61 | OpenDialog.Title = "Load Kernel.img"; 62 | OpenDialog.Filter = "Image|*.img"; 63 | 64 | if (OpenDialog.ShowDialog() == DialogResult.OK && File.Exists(OpenDialog.FileName)) 65 | { 66 | RaspberryPi.Load(OpenDialog.FileName, 0x8000, true); 67 | RaspberryPi.RunAsync(); 68 | } 69 | } 70 | } 71 | 72 | private void MnuDumpSDRAM_Click(object sender, EventArgs e) 73 | { 74 | File.WriteAllBytes(@"D:\pimem.bin", RaspberryPi.Memory.SDRAM); 75 | } 76 | 77 | private void ScreenRefresh_Tick(object sender, EventArgs e) 78 | { 79 | Bitmap Img = RaspberryPi.Memory.Video.GetImage(); 80 | if (Img != null) Screen.Image = Img; 81 | } 82 | 83 | private void MnuShowUART_Click(object sender, EventArgs e) 84 | { 85 | FrmUARTOutput Form = new FrmUARTOutput(RaspberryPi); 86 | Form.Show(); 87 | } 88 | 89 | private void MnuARMDbg_Click(object sender, EventArgs e) 90 | { 91 | RaspberryPi.CPU.Debug = !RaspberryPi.CPU.Debug; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /ChocolateARM/FrmMain.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 118, 17 125 | 126 | 127 | 341, 17 128 | 129 | -------------------------------------------------------------------------------- /ChocolateARM/FrmUARTOutput.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ChocolateARM 2 | { 3 | partial class FrmUARTOutput 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.Tabs = new System.Windows.Forms.TabControl(); 32 | this.TabMiniUART = new System.Windows.Forms.TabPage(); 33 | this.TabUART = new System.Windows.Forms.TabPage(); 34 | this.BtnOk = new System.Windows.Forms.Button(); 35 | this.TxtMiniUART = new System.Windows.Forms.TextBox(); 36 | this.TxtUART = new System.Windows.Forms.TextBox(); 37 | this.BtnClear = new System.Windows.Forms.Button(); 38 | this.BtnClearAll = new System.Windows.Forms.Button(); 39 | this.Tabs.SuspendLayout(); 40 | this.TabMiniUART.SuspendLayout(); 41 | this.TabUART.SuspendLayout(); 42 | this.SuspendLayout(); 43 | // 44 | // Tabs 45 | // 46 | this.Tabs.Controls.Add(this.TabMiniUART); 47 | this.Tabs.Controls.Add(this.TabUART); 48 | this.Tabs.Dock = System.Windows.Forms.DockStyle.Top; 49 | this.Tabs.Location = new System.Drawing.Point(0, 0); 50 | this.Tabs.Name = "Tabs"; 51 | this.Tabs.SelectedIndex = 0; 52 | this.Tabs.Size = new System.Drawing.Size(584, 319); 53 | this.Tabs.TabIndex = 0; 54 | // 55 | // TabMiniUART 56 | // 57 | this.TabMiniUART.Controls.Add(this.TxtMiniUART); 58 | this.TabMiniUART.Location = new System.Drawing.Point(4, 22); 59 | this.TabMiniUART.Name = "TabMiniUART"; 60 | this.TabMiniUART.Padding = new System.Windows.Forms.Padding(3); 61 | this.TabMiniUART.Size = new System.Drawing.Size(576, 293); 62 | this.TabMiniUART.TabIndex = 0; 63 | this.TabMiniUART.Text = "Mini UART"; 64 | this.TabMiniUART.UseVisualStyleBackColor = true; 65 | // 66 | // TabUART 67 | // 68 | this.TabUART.Controls.Add(this.TxtUART); 69 | this.TabUART.Location = new System.Drawing.Point(4, 22); 70 | this.TabUART.Name = "TabUART"; 71 | this.TabUART.Padding = new System.Windows.Forms.Padding(3); 72 | this.TabUART.Size = new System.Drawing.Size(576, 293); 73 | this.TabUART.TabIndex = 1; 74 | this.TabUART.Text = "UART (PL011)"; 75 | this.TabUART.UseVisualStyleBackColor = true; 76 | // 77 | // BtnOk 78 | // 79 | this.BtnOk.Location = new System.Drawing.Point(481, 325); 80 | this.BtnOk.Name = "BtnOk"; 81 | this.BtnOk.Size = new System.Drawing.Size(96, 24); 82 | this.BtnOk.TabIndex = 1; 83 | this.BtnOk.Text = "&OK"; 84 | this.BtnOk.UseVisualStyleBackColor = true; 85 | this.BtnOk.Click += new System.EventHandler(this.BtnOk_Click); 86 | // 87 | // TxtMiniUART 88 | // 89 | this.TxtMiniUART.BackColor = System.Drawing.Color.Black; 90 | this.TxtMiniUART.Dock = System.Windows.Forms.DockStyle.Fill; 91 | this.TxtMiniUART.ForeColor = System.Drawing.Color.White; 92 | this.TxtMiniUART.Location = new System.Drawing.Point(3, 3); 93 | this.TxtMiniUART.Multiline = true; 94 | this.TxtMiniUART.Name = "TxtMiniUART"; 95 | this.TxtMiniUART.ReadOnly = true; 96 | this.TxtMiniUART.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 97 | this.TxtMiniUART.Size = new System.Drawing.Size(570, 287); 98 | this.TxtMiniUART.TabIndex = 0; 99 | // 100 | // TxtUART 101 | // 102 | this.TxtUART.BackColor = System.Drawing.Color.Black; 103 | this.TxtUART.Dock = System.Windows.Forms.DockStyle.Fill; 104 | this.TxtUART.ForeColor = System.Drawing.Color.White; 105 | this.TxtUART.Location = new System.Drawing.Point(3, 3); 106 | this.TxtUART.Multiline = true; 107 | this.TxtUART.Name = "TxtUART"; 108 | this.TxtUART.ReadOnly = true; 109 | this.TxtUART.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 110 | this.TxtUART.Size = new System.Drawing.Size(570, 287); 111 | this.TxtUART.TabIndex = 1; 112 | // 113 | // BtnClear 114 | // 115 | this.BtnClear.Location = new System.Drawing.Point(7, 325); 116 | this.BtnClear.Name = "BtnClear"; 117 | this.BtnClear.Size = new System.Drawing.Size(96, 24); 118 | this.BtnClear.TabIndex = 2; 119 | this.BtnClear.Text = "&Clear"; 120 | this.BtnClear.UseVisualStyleBackColor = true; 121 | this.BtnClear.Click += new System.EventHandler(this.BtnClear_Click); 122 | // 123 | // BtnClearAll 124 | // 125 | this.BtnClearAll.Location = new System.Drawing.Point(109, 325); 126 | this.BtnClearAll.Name = "BtnClearAll"; 127 | this.BtnClearAll.Size = new System.Drawing.Size(96, 24); 128 | this.BtnClearAll.TabIndex = 3; 129 | this.BtnClearAll.Text = "&Clear all"; 130 | this.BtnClearAll.UseVisualStyleBackColor = true; 131 | this.BtnClearAll.Click += new System.EventHandler(this.BtnClearAll_Click); 132 | // 133 | // FrmUARTOutput 134 | // 135 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 136 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 137 | this.ClientSize = new System.Drawing.Size(584, 361); 138 | this.Controls.Add(this.BtnClearAll); 139 | this.Controls.Add(this.BtnClear); 140 | this.Controls.Add(this.BtnOk); 141 | this.Controls.Add(this.Tabs); 142 | this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 143 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 144 | this.MaximizeBox = false; 145 | this.Name = "FrmUARTOutput"; 146 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 147 | this.Text = "UART Output"; 148 | this.Load += new System.EventHandler(this.FrmUARTOutput_Load); 149 | this.Tabs.ResumeLayout(false); 150 | this.TabMiniUART.ResumeLayout(false); 151 | this.TabMiniUART.PerformLayout(); 152 | this.TabUART.ResumeLayout(false); 153 | this.TabUART.PerformLayout(); 154 | this.ResumeLayout(false); 155 | 156 | } 157 | 158 | #endregion 159 | 160 | private System.Windows.Forms.TabControl Tabs; 161 | private System.Windows.Forms.TabPage TabMiniUART; 162 | private System.Windows.Forms.TextBox TxtMiniUART; 163 | private System.Windows.Forms.TabPage TabUART; 164 | private System.Windows.Forms.TextBox TxtUART; 165 | private System.Windows.Forms.Button BtnOk; 166 | private System.Windows.Forms.Button BtnClear; 167 | private System.Windows.Forms.Button BtnClearAll; 168 | } 169 | } -------------------------------------------------------------------------------- /ChocolateARM/FrmUARTOutput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | using ChocolateARM.RPi; 5 | using ChocolateARM.RPi.Peripherals; 6 | 7 | namespace ChocolateARM 8 | { 9 | public partial class FrmUARTOutput : Form 10 | { 11 | RPiCore RaspberryPi; 12 | 13 | public FrmUARTOutput(RPiCore RaspberryPi) 14 | { 15 | this.RaspberryPi = RaspberryPi; 16 | 17 | InitializeComponent(); 18 | } 19 | 20 | private void FrmUARTOutput_Load(object sender, EventArgs e) 21 | { 22 | Show(); 23 | 24 | CharacterReceived = new CharacterReceivedDelegate(ReceiveCharacter); 25 | 26 | //Update texts 27 | TxtMiniUART.AppendText(RaspberryPi.Memory.MiniUART.BufferedOutput ?? ""); 28 | TxtUART.AppendText(RaspberryPi.Memory.UART.BufferedOutput ?? ""); 29 | 30 | //And subscribe for new characters 31 | RaspberryPi.Memory.MiniUART.OnCharacterReceived += MU_CharacterReceived; 32 | RaspberryPi.Memory.UART.OnCharacterReceived += UART_CharacterReceived; 33 | } 34 | 35 | private CharacterReceivedDelegate CharacterReceived; 36 | private delegate void CharacterReceivedDelegate(TextBox Target, char Character); 37 | 38 | private void MU_CharacterReceived(object sender, CharacterReceivedEventArgs e) 39 | { 40 | BeginInvoke(CharacterReceived, TxtMiniUART, e.Character); 41 | } 42 | 43 | private void UART_CharacterReceived(object sender, CharacterReceivedEventArgs e) 44 | { 45 | BeginInvoke(CharacterReceived, TxtUART, e.Character); 46 | } 47 | 48 | private void ReceiveCharacter(TextBox Target, char Character) 49 | { 50 | Target.AppendText(Character.ToString()); 51 | } 52 | 53 | private void BtnOk_Click(object sender, EventArgs e) 54 | { 55 | Close(); 56 | } 57 | 58 | private void BtnClear_Click(object sender, EventArgs e) 59 | { 60 | if (Tabs.SelectedIndex == 0) 61 | TxtMiniUART.Clear(); 62 | else 63 | TxtUART.Clear(); 64 | } 65 | 66 | private void BtnClearAll_Click(object sender, EventArgs e) 67 | { 68 | TxtMiniUART.Clear(); 69 | TxtUART.Clear(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /ChocolateARM/FrmUARTOutput.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /ChocolateARM/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace ChocolateARM 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new FrmMain()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ChocolateARM/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ChocolateARM")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ChocolateARM")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("47232f73-385b-43d6-8751-10b289daebe1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ChocolateARM/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ChocolateARM.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ChocolateARM.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ChocolateARM/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /ChocolateARM/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ChocolateARM.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ChocolateARM/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ChocolateARM/RPi/IO32.cs: -------------------------------------------------------------------------------- 1 | namespace ChocolateARM.RPi 2 | { 3 | /// 4 | /// "Converts" a sequence of 8-bits writes (or reads) into 32-bits values. 5 | /// This class must be inherited, and the ProcessRead and ProcessWrite methods overloaded. 6 | /// 7 | public abstract class IO32 8 | { 9 | private uint ReadValue; 10 | private uint WriteValue; 11 | 12 | /// 13 | /// Reads Data from the IO region. 14 | /// 15 | /// The Address that is being read 16 | /// The Data on the Address 17 | public byte Read(uint Address) 18 | { 19 | switch (Address & 3) 20 | { 21 | case 0: 22 | ReadValue = ProcessRead(Address); 23 | return (byte)ReadValue; 24 | case 1: return (byte)(ReadValue >> 8); 25 | case 2: return (byte)(ReadValue >> 16); 26 | case 3: return (byte)(ReadValue >> 24); 27 | } 28 | 29 | return 0; 30 | } 31 | 32 | /// 33 | /// Writes Data to the IO region. 34 | /// 35 | /// The Address where the Value is being written 36 | /// The Value that is being written 37 | public void Write(uint Address, byte Value) 38 | { 39 | switch (Address & 3) 40 | { 41 | case 0: WriteValue = Value; break; 42 | case 1: WriteValue |= (uint)(Value << 8); break; 43 | case 2: WriteValue |= (uint)(Value << 16); break; 44 | case 3: 45 | WriteValue |= (uint)(Value << 24); 46 | ProcessWrite(Address & 0xfffffffc, WriteValue); 47 | break; 48 | } 49 | } 50 | 51 | /// 52 | /// This method is called whenever a new Read request has arrived. 53 | /// 54 | /// The Address where the Read operation was made 55 | /// The Data on the Address 56 | public abstract uint ProcessRead(uint Address); 57 | 58 | /// 59 | /// This method is called whenever a new Write operation is made. 60 | /// 61 | /// The Address where the Write operation was made 62 | /// The value being written 63 | public abstract void ProcessWrite(uint Address, uint Value); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ChocolateARM/RPi/Memory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | using SharpARM.ARM11; 4 | 5 | using ChocolateARM.RPi.Peripherals; 6 | 7 | namespace ChocolateARM.RPi 8 | { 9 | /// 10 | /// Represents the Memory and IO of the BCM2835 SoC. 11 | /// 12 | public class Memory : IBus 13 | { 14 | const uint KB = 1024; 15 | const uint MB = 1024 * KB; 16 | 17 | public byte[] SDRAM; 18 | 19 | public RPiDMA DMA; 20 | public RPiTimer Timer; 21 | public VideoCore Video; 22 | public RPiUART UART; 23 | public RPiMiniUART MiniUART; 24 | 25 | /// 26 | /// Creates a new instance of the RaspberryPi memory manager. 27 | /// 28 | public Memory() 29 | { 30 | SDRAM = new byte[256 * MB]; 31 | 32 | DMA = new RPiDMA(this); 33 | Timer = new RPiTimer(); 34 | Video = new VideoCore(this); 35 | UART = new RPiUART(); 36 | MiniUART = new RPiMiniUART(this); 37 | } 38 | 39 | /// 40 | /// Reads 8-bits from Memory. 41 | /// 42 | /// The Address to read 43 | /// The value at the given Address 44 | public byte ReadUInt8(uint Address) 45 | { 46 | Address &= 0x3fffffff; 47 | 48 | if (Address < SDRAM.Length) 49 | return SDRAM[Address]; 50 | else if (Address >= 0x20007000 && Address < 0x20008000) 51 | return DMA.Read(Address); 52 | else if (Address >= 0x2000b400 && Address < 0x2000b424) 53 | return Timer.Read(Address); 54 | else if (Address >= 0x2000b880 && Address < 0x2000b8b0) 55 | return Video.Read(Address); 56 | else if (Address >= 0x20201000 && Address < 0x20201090) 57 | return UART.Read(Address); 58 | else if (Address >= 0x20215000 && Address < 0x20215080) 59 | return MiniUART.Read(Address); 60 | 61 | return 0; 62 | } 63 | 64 | /// 65 | /// Reads 32-bits from Memory. 66 | /// 67 | /// The Address to read 68 | /// The value at the given Address 69 | public uint ReadUInt32(uint Address) 70 | { 71 | return (uint)(ReadUInt8(Address) | 72 | (ReadUInt8(Address + 1) << 8) | 73 | (ReadUInt8(Address + 2) << 16) | 74 | (ReadUInt8(Address + 3) << 24)); 75 | } 76 | 77 | /// 78 | /// Writes 8-bits to Memory. 79 | /// 80 | /// The Address to write the value into 81 | /// The value to be written 82 | public void WriteUInt8(uint Address, byte Value) 83 | { 84 | Address &= 0x3fffffff; 85 | 86 | if (Address < SDRAM.Length) 87 | SDRAM[Address] = Value; 88 | else if (Address >= 0x20007000 && Address < 0x20008000) 89 | DMA.Write(Address, Value); 90 | else if (Address >= 0x2000b400 && Address < 0x2000b424) 91 | Timer.Write(Address, Value); 92 | else if (Address >= 0x2000b880 && Address < 0x2000b8b0) 93 | Video.Write(Address, Value); 94 | else if (Address >= 0x20201000 && Address < 0x20201090) 95 | UART.Write(Address, Value); 96 | else if (Address >= 0x20215000 && Address < 0x20215080) 97 | MiniUART.Write(Address, Value); 98 | } 99 | 100 | /// 101 | /// Writes 32-bits to Memory. 102 | /// 103 | /// The Address to write the value into 104 | /// The value to be written 105 | public void WriteUInt32(uint Address, uint Value) 106 | { 107 | WriteUInt8(Address, (byte)Value); 108 | WriteUInt8(Address + 1, (byte)(Value >> 8)); 109 | WriteUInt8(Address + 2, (byte)(Value >> 16)); 110 | WriteUInt8(Address + 3, (byte)(Value >> 24)); 111 | } 112 | 113 | /// 114 | /// Copy data from one region to another of the Memory. 115 | /// 116 | /// The Source Address to start copying from 117 | /// Where the data should be placed 118 | /// Number of bytes to copy 119 | public void CopyData(uint Source, uint Destination, uint Length) 120 | { 121 | Buffer.BlockCopy(SDRAM, (int)Source, SDRAM, (int)Destination, (int)Length); 122 | } 123 | 124 | /// 125 | /// Gets a Buffer at a given Address of the SDRAM. 126 | /// 127 | /// The Address where the Buffer is located 128 | /// The length of the Buffer 129 | /// The Buffer 130 | public byte[] GetData(uint Address, uint Length) 131 | { 132 | Address &= 0x3fffffff; 133 | 134 | byte[] Output = new byte[Length]; 135 | Buffer.BlockCopy(SDRAM, (int)Address, Output, 0, Output.Length); 136 | return Output; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /ChocolateARM/RPi/Peripherals/RPiDMA.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ChocolateARM.RPi.Peripherals 4 | { 5 | /// 6 | /// Represents the DMA control of the BCM2835 SoC. 7 | /// 8 | public class RPiDMA : IO32 9 | { 10 | private Memory Parent; 11 | 12 | /// 13 | /// Creates a new instace of the RaspberryPi DMA manager. 14 | /// 15 | public RPiDMA(Memory Parent) 16 | { 17 | this.Parent = Parent; 18 | DMA = new DMA_Channel[16]; 19 | } 20 | 21 | private struct DMA_Control 22 | { 23 | public bool IsActive; 24 | public bool IsFinished; 25 | public bool IsInterruptTriggered; 26 | 27 | /// 28 | /// Loads the value of the DMA Control from a UInt32. 29 | /// 30 | /// The UInt32 Control value 31 | public void Set(uint Value) 32 | { 33 | IsActive = (Value & 1) != 0; 34 | if ((Value & 2) != 0) IsFinished = false; 35 | if ((Value & 4) != 0) IsInterruptTriggered = false; 36 | } 37 | 38 | /// 39 | /// Creates a UInt32 from the values of the DMA Control. 40 | /// 41 | /// The Control value 42 | public uint Get() 43 | { 44 | uint Value = 0; 45 | if (IsActive) Value = 1; 46 | if (IsFinished) Value |= 2; 47 | if (IsInterruptTriggered) Value |= 4; 48 | if (!IsActive) Value |= 0x10; 49 | return Value; 50 | } 51 | } 52 | 53 | private struct DMA_Channel 54 | { 55 | public bool IsEnabled; 56 | 57 | public DMA_Control Control; 58 | public uint ControlBlockAddress; 59 | } 60 | private DMA_Channel[] DMA; 61 | 62 | /// 63 | /// Occurs when a interrupt is triggered. 64 | /// 65 | public event Action OnInterruptRequest; 66 | 67 | /// 68 | /// Reads a 32-bits value from the Register. 69 | /// 70 | /// The Address being read 71 | /// The value of the Register 72 | public override uint ProcessRead(uint Address) 73 | { 74 | uint Value = 0; 75 | 76 | if (Address >= 0x20007000 && Address < 0x20007f00) 77 | DMA_ProcessRead(Address, (Address >> 8) & 0xf); 78 | else if (Address == 0x20007ff0) 79 | { 80 | for (int Index = 0; Index < 16; Index++) 81 | { 82 | if (DMA[Index].IsEnabled) Value |= (uint)(1 << Index); 83 | } 84 | } 85 | 86 | return Value; 87 | } 88 | 89 | /// 90 | /// Writes a 32-bits value to a Register. 91 | /// 92 | /// The Address being written 93 | /// The value being written 94 | public override void ProcessWrite(uint Address, uint Value) 95 | { 96 | if (Address >= 0x20007000 && Address < 0x20007f00) 97 | DMA_ProcessWrite(Address, Value, (Address >> 8) & 0xf); 98 | else if (Address == 0x20007ff0) 99 | { 100 | for (int Index = 0; Index < 16; Index++) 101 | { 102 | DMA[Index].IsEnabled = (Value & (1 << Index)) != 0; 103 | } 104 | } 105 | } 106 | 107 | /// 108 | /// Reads a value from a DMA Channel. 109 | /// 110 | /// The Address being read 111 | /// The Channel being read 112 | /// The value of the Channel register being read 113 | private uint DMA_ProcessRead(uint Address, uint Channel) 114 | { 115 | Address &= 0xff; 116 | 117 | switch (Address) 118 | { 119 | case 0: return DMA[Channel].Control.Get(); 120 | case 4: return DMA[Channel].ControlBlockAddress; 121 | case 0x20: 122 | uint Value = 0x4000000; //DMA Version (always 2) 123 | if (Channel > 6) Value |= 0x10000000; //Lite 124 | return Value; 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | /// 131 | /// Writes a value to a DMA Channel. 132 | /// 133 | /// The Address being written 134 | /// The Value being written 135 | /// The Channel being written 136 | private void DMA_ProcessWrite(uint Address, uint Value, uint Channel) 137 | { 138 | Address &= 0xff; 139 | 140 | switch (Address) 141 | { 142 | case 0: DMA[Channel].Control.Set(Value); break; 143 | case 4: DMA[Channel].ControlBlockAddress = Value; break; 144 | } 145 | 146 | DMA_Transfer(Channel); 147 | } 148 | 149 | /// 150 | /// Performs a DMA transfer (if any is pending). 151 | /// 152 | /// The Channel that is transferring data 153 | private void DMA_Transfer(uint Channel) 154 | { 155 | if (DMA[Channel].IsEnabled && DMA[Channel].Control.IsActive) 156 | { 157 | while (DMA[Channel].ControlBlockAddress > 0) 158 | { 159 | uint Address = DMA[Channel].ControlBlockAddress; 160 | 161 | uint TransferInformation = Parent.ReadUInt32(Address); 162 | uint SrcAddress = Parent.ReadUInt32(Address + 4); 163 | uint DstAddress = Parent.ReadUInt32(Address + 8); 164 | uint Length = Parent.ReadUInt32(Address + 12); 165 | uint Stride = Parent.ReadUInt32(Address + 16); 166 | uint NextAddress = Parent.ReadUInt32(Address + 20); 167 | 168 | bool IsInterruptEnabled = (TransferInformation & 1) != 0; 169 | bool Is2DModeEnabled = (TransferInformation & 2) != 0; 170 | 171 | if (Channel < 7) 172 | { 173 | if (Is2DModeEnabled) 174 | { 175 | //2D Array transfer 176 | short SrcStride = (short)Stride; 177 | short DstStride = (short)(Stride >> 16); 178 | 179 | ushort XLength = (ushort)Length; 180 | ushort YLength = (ushort)(Length >> 16); 181 | 182 | for (int Y = 0; Y < YLength; Y++) 183 | { 184 | Parent.CopyData(SrcAddress, DstAddress, XLength); 185 | 186 | SrcAddress = (uint)(SrcAddress + XLength + SrcStride); 187 | DstAddress = (uint)(DstAddress + XLength + DstStride); 188 | } 189 | } 190 | else 191 | Parent.CopyData(SrcAddress, DstAddress, Length); //Normal 1D transfer 192 | } 193 | else 194 | Parent.CopyData(SrcAddress, DstAddress, (ushort)Length); //Lite, always 1D with 16-bits length 195 | 196 | //Trigger interrupts if needed 197 | if (IsInterruptEnabled) 198 | { 199 | if (OnInterruptRequest != null) OnInterruptRequest(); 200 | DMA[Channel].Control.IsInterruptTriggered = true; 201 | } 202 | 203 | DMA[Channel].ControlBlockAddress = NextAddress; 204 | } 205 | 206 | DMA[Channel].Control.IsActive = false; 207 | DMA[Channel].Control.IsFinished = true; 208 | } 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /ChocolateARM/RPi/Peripherals/RPiMiniUART.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ChocolateARM.RPi.Peripherals 5 | { 6 | /// 7 | /// Represents a new character that arrived at the UART. 8 | /// 9 | public class CharacterReceivedEventArgs : EventArgs 10 | { 11 | /// 12 | /// The new character that arrived on the UART. 13 | /// 14 | public char Character; 15 | 16 | /// 17 | /// Creates a new Argument with the character written to the UART. 18 | /// 19 | /// The new character 20 | public CharacterReceivedEventArgs(char Character) 21 | { 22 | this.Character = Character; 23 | } 24 | } 25 | 26 | /// 27 | /// Represents the Mini UART of the BCM2835 SoC. 28 | /// 29 | public class RPiMiniUART : IO32 30 | { 31 | private const uint AUX_ENB = 0x20215004; 32 | private const uint AUX_MU_IO_REG = 0x20215040; 33 | private const uint AUX_MU_IIR_REG = 0x20215044; 34 | private const uint AUX_MU_IER_REG = 0x20215048; 35 | private const uint AUX_MU_LCR_REG = 0x2021504c; 36 | private const uint AUX_MU_MCR_REG = 0x20215050; 37 | private const uint AUX_MU_LSR_REG = 0x20215054; 38 | private const uint AUX_MU_MSR_REG = 0x20215058; 39 | private const uint AUX_MU_SCRATCH = 0x2021505c; 40 | private const uint AUX_MU_CNTL_REG = 0x20215060; 41 | private const uint AUX_MU_STAT_REG = 0x20215064; 42 | private const uint AUX_MU_BAUD_REG = 0x20215068; 43 | 44 | private Memory Parent; 45 | 46 | private Queue Transmitter; 47 | private Queue Receiver; 48 | 49 | /// 50 | /// Creates a new instace of the RaspberryPi Mini UART. 51 | /// 52 | public RPiMiniUART(Memory Parent) 53 | { 54 | this.Parent = Parent; 55 | Transmitter = new Queue(); 56 | Receiver = new Queue(); 57 | 58 | MU_IsReceiverEnabled = true; 59 | MU_IsTransmitterEnabled = true; 60 | } 61 | 62 | private bool MU_IsEnabled; 63 | private bool SPI1_IsEnabled; 64 | private bool SPI2_IsEnabled; 65 | 66 | private bool MU_IsTransmitInterruptEnabled; 67 | private bool MU_IsReceiveInterruptEnabled; 68 | private bool MU_8BitsMode; 69 | private bool MU_DLAB; 70 | private bool MU_ReceiverOverrun; 71 | private byte MU_Scratch; 72 | private bool MU_IsReceiverEnabled; 73 | private bool MU_IsTransmitterEnabled; 74 | private ushort MU_BaudRate; 75 | 76 | /// 77 | /// Occurs when a interrupt is triggered. 78 | /// 79 | public event Action OnInterruptRequest; 80 | 81 | /// 82 | /// Occurs whenever a new character is written to the UART. 83 | /// 84 | public event EventHandler OnCharacterReceived; 85 | 86 | /// 87 | /// Contains a copy of all data written to the UART. 88 | /// 89 | public string BufferedOutput { get; private set; } 90 | 91 | /// 92 | /// Reads a 32-bits value from the Register. 93 | /// 94 | /// The Address being read 95 | /// The value of the Register 96 | public override uint ProcessRead(uint Address) 97 | { 98 | uint Value = 0; 99 | 100 | switch (Address) 101 | { 102 | case AUX_ENB: 103 | if (MU_IsEnabled) Value = 1; 104 | if (SPI1_IsEnabled) Value |= 2; 105 | if (SPI2_IsEnabled) Value |= 4; 106 | break; 107 | 108 | case AUX_MU_IO_REG: 109 | if (MU_DLAB) 110 | Value = (uint)(MU_BaudRate & 0xff); 111 | else if (Receiver.Count > 0) 112 | Value = Receiver.Dequeue(); 113 | break; 114 | 115 | case AUX_MU_IIR_REG: 116 | if (MU_DLAB) 117 | Value = (uint)(MU_BaudRate >> 8); 118 | else 119 | { 120 | if (MU_IsReceiveInterruptEnabled) Value = 1; 121 | if (MU_IsTransmitInterruptEnabled) Value |= 2; 122 | } 123 | break; 124 | 125 | case AUX_MU_IER_REG: 126 | Value = 0xc1; 127 | if (Transmitter.Count == 0) Value |= 2; 128 | if (Receiver.Count > 0) Value |= 4; 129 | break; 130 | 131 | case AUX_MU_LCR_REG: 132 | if (MU_8BitsMode) Value = 1; 133 | if (MU_DLAB) Value |= 0x80; 134 | break; 135 | 136 | case AUX_MU_LSR_REG: 137 | if (Receiver.Count > 0) Value = 1; 138 | if (MU_ReceiverOverrun) 139 | { 140 | Value |= 2; 141 | MU_ReceiverOverrun = false; 142 | } 143 | if (Transmitter.Count < 8) Value |= 0x20; 144 | if (Transmitter.Count == 0) Value |= 0x40; 145 | break; 146 | 147 | case AUX_MU_SCRATCH: Value = MU_Scratch; break; 148 | 149 | case AUX_MU_CNTL_REG: 150 | if (MU_IsReceiverEnabled) Value = 1; 151 | if (MU_IsTransmitterEnabled) Value |= 2; 152 | break; 153 | 154 | case AUX_MU_STAT_REG: 155 | Value = 0xc; 156 | if (Receiver.Count > 0) Value |= 1; 157 | if (Transmitter.Count < 8) Value |= 2; 158 | if (MU_ReceiverOverrun) Value |= 0x10; 159 | if (Transmitter.Count == 8) Value |= 0x20; 160 | if (Transmitter.Count == 0) Value |= 0x300; 161 | Value |= (uint)((Receiver.Count & 0xf) << 16); 162 | Value |= (uint)((Transmitter.Count & 0xf) << 24); 163 | break; 164 | 165 | case AUX_MU_BAUD_REG: Value = MU_BaudRate; break; 166 | } 167 | 168 | return Value; 169 | } 170 | 171 | /// 172 | /// Writes a 32-bits value to a Register. 173 | /// 174 | /// The Address being written 175 | /// The value being written 176 | public override void ProcessWrite(uint Address, uint Value) 177 | { 178 | if (Address >= 0x20215040 && !MU_IsEnabled) return; 179 | 180 | switch (Address) 181 | { 182 | case AUX_ENB: 183 | MU_IsEnabled = (Value & 1) != 0; 184 | SPI1_IsEnabled = (Value & 2) != 0; 185 | SPI2_IsEnabled = (Value & 4) != 0; 186 | break; 187 | 188 | case AUX_MU_IO_REG: 189 | if (MU_DLAB) 190 | MU_BaudRate = (ushort)((MU_BaudRate & 0xff00) | (byte)Value); 191 | else if (Transmitter.Count < 8 && MU_IsTransmitterEnabled) 192 | { 193 | Transmitter.Enqueue((byte)Value); 194 | AppendCharacter(); 195 | } 196 | break; 197 | 198 | case AUX_MU_IIR_REG: 199 | if (MU_DLAB) 200 | MU_BaudRate = (ushort)((MU_BaudRate & 0xff) | ((byte)Value << 8)); 201 | else 202 | { 203 | MU_IsReceiveInterruptEnabled = (Value & 1) != 0; 204 | MU_IsTransmitInterruptEnabled = (Value & 2) != 0; 205 | } 206 | break; 207 | 208 | case AUX_MU_IER_REG: 209 | if ((Value & 2) != 0) Receiver.Clear(); 210 | if ((Value & 4) != 0) Transmitter.Clear(); 211 | break; 212 | 213 | case AUX_MU_LCR_REG: 214 | MU_8BitsMode = (Value & 1) != 0; 215 | MU_DLAB = (Value & 0x80) != 0; 216 | break; 217 | 218 | case AUX_MU_SCRATCH: MU_Scratch = (byte)Value; break; 219 | 220 | case AUX_MU_CNTL_REG: 221 | MU_IsReceiverEnabled = (Value & 1) != 0; 222 | MU_IsTransmitterEnabled = (Value & 2) != 0; 223 | break; 224 | 225 | case AUX_MU_BAUD_REG: MU_BaudRate = (ushort)Value; break; 226 | } 227 | } 228 | 229 | /// 230 | /// Appends a character on the console. 231 | /// 232 | private void AppendCharacter() 233 | { 234 | char Character = (char)Transmitter.Dequeue(); 235 | if (OnCharacterReceived != null) OnCharacterReceived(this, new CharacterReceivedEventArgs(Character)); 236 | BufferedOutput += Character; 237 | 238 | bool TriggerInterrupt = Transmitter.Count == 0 && MU_IsTransmitInterruptEnabled; 239 | if (TriggerInterrupt && OnInterruptRequest != null) OnInterruptRequest(); 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /ChocolateARM/RPi/Peripherals/RPiTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Timers; 3 | 4 | namespace ChocolateARM.RPi.Peripherals 5 | { 6 | /// 7 | /// Represents the Timer of the BCM2835 SoC. 8 | /// 9 | public class RPiTimer : IO32, IDisposable 10 | { 11 | const double ARMT_Frequency = 1000000; //1MHz 12 | 13 | private uint ARMT_LoadValue; 14 | private uint ARMT_Value; 15 | private uint ARMT_Control; 16 | private uint ARMT_Reload; 17 | private uint ARMT_PreDivider; 18 | private uint ARMT_FreeRunCounter; 19 | 20 | private Timer Countdown; 21 | private Timer FreeRun; 22 | 23 | /// 24 | /// Occurs when a interrupt is triggered. 25 | /// 26 | public event Action OnInterruptRequest; 27 | 28 | public void Dispose() 29 | { 30 | Dispose(true); 31 | GC.SuppressFinalize(this); 32 | } 33 | 34 | protected virtual void Dispose(bool Disposing) 35 | { 36 | if (Disposing) 37 | { 38 | Countdown.Dispose(); 39 | FreeRun.Dispose(); 40 | } 41 | } 42 | 43 | /// 44 | /// Creates a new instace of the RaspberryPi Timer. 45 | /// 46 | public RPiTimer() 47 | { 48 | ARMT_Control = 0x3e0020; 49 | ARMT_PreDivider = 0x7d; 50 | 51 | Countdown = new Timer(); 52 | FreeRun = new Timer(); 53 | 54 | Countdown.Elapsed += Countdown_Tick; 55 | FreeRun.Elapsed += FreeRun_Tick; 56 | } 57 | 58 | /// 59 | /// Reads a value from the Timer registers. 60 | /// 61 | /// The Address of the read 62 | /// The value at the Address 63 | public override uint ProcessRead(uint Address) 64 | { 65 | switch (Address) 66 | { 67 | case 0x2000b400: return ARMT_LoadValue; 68 | case 0x2000b404: 69 | if ((ARMT_Control & 2) != 0) 70 | ARMT_Value &= 0x7fffff; 71 | else 72 | ARMT_Value &= 0xffff; 73 | return ARMT_Value; 74 | case 0x2000b408: return ARMT_Control; 75 | case 0x2000b40c: return 0x544d5241; 76 | case 0x2000b410: return 0x3e0020; 77 | case 0x2000b414: return 0x3e0020; 78 | case 0x2000b418: return ARMT_Reload; 79 | case 0x2000b41c: return ARMT_PreDivider; 80 | case 0x2000b420: return ARMT_FreeRunCounter; 81 | } 82 | 83 | return 0; 84 | } 85 | 86 | /// 87 | /// Writes a value to the Timer registers. 88 | /// 89 | /// The Address of the write 90 | /// The value being written 91 | public override void ProcessWrite(uint Address, uint Value) 92 | { 93 | switch (Address) 94 | { 95 | case 0x2000b400: 96 | ARMT_LoadValue = Value; 97 | ARMT_Value = Value; 98 | break; 99 | case 0x2000b408: 100 | ARMT_Control = Value; 101 | switch ((Value >> 2) & 3) 102 | { 103 | case 1: Countdown.Interval = 1000d / (ARMT_Frequency / 16); break; 104 | case 2: Countdown.Interval = 1000d / (ARMT_Frequency / 256); break; 105 | default: Countdown.Interval = 1000d / ARMT_Frequency; break; 106 | } 107 | Countdown.Enabled = (Value & 0x80) != 0; 108 | FreeRun.Enabled = (Value & 0x200) != 0; 109 | FreeRun.Interval = 1000d / (ARMT_Frequency / (((Value >> 16) & 0xff) + 1)); 110 | break; 111 | case 0x2000b418: ARMT_Reload = Value; break; 112 | case 0x2000b41c: ARMT_PreDivider = Value; break; 113 | case 0x2000b420: ARMT_FreeRunCounter = Value; break; 114 | } 115 | } 116 | 117 | private void Countdown_Tick(object sender, ElapsedEventArgs e) 118 | { 119 | if (ARMT_Value > 0) 120 | ARMT_Value--; 121 | else 122 | { 123 | ARMT_Value = ARMT_LoadValue; 124 | bool IsInterruptEnabled = (ARMT_Control & 0x20) != 0; 125 | if (IsInterruptEnabled && OnInterruptRequest != null) OnInterruptRequest(); 126 | } 127 | } 128 | 129 | private void FreeRun_Tick(object sender, ElapsedEventArgs e) 130 | { 131 | ARMT_FreeRunCounter++; 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /ChocolateARM/RPi/Peripherals/RPiUART.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ChocolateARM.RPi.Peripherals 5 | { 6 | /// 7 | /// Represents the UART (PL011) of the BCM2835 SoC. 8 | /// 9 | public class RPiUART : IO32 10 | { 11 | private Queue Transmitter; 12 | private Queue Receiver; 13 | 14 | /// 15 | /// Occurs when a interrupt is triggered. 16 | /// 17 | public event Action OnInterruptRequest; 18 | 19 | /// 20 | /// Occurs whenever a new character is written to the UART. 21 | /// 22 | public event EventHandler OnCharacterReceived; 23 | 24 | /// 25 | /// Contains a copy of all data written to the UART. 26 | /// 27 | public string BufferedOutput { get; private set; } 28 | 29 | public RPiUART() 30 | { 31 | Transmitter = new Queue(); 32 | Receiver = new Queue(); 33 | } 34 | 35 | /// 36 | /// Reads a 32-bits value from the Register. 37 | /// 38 | /// The Address being read 39 | /// The value of the Register 40 | public override uint ProcessRead(uint Address) 41 | { 42 | switch (Address) 43 | { 44 | case 0x20201000: if (Receiver.Count > 0) return Receiver.Dequeue(); break; 45 | case 0x20201018: 46 | uint Value = 0; 47 | if (Receiver.Count == 0) Value = 0x10; 48 | if (Transmitter.Count == 8) Value |= 0x20; 49 | if (Receiver.Count == 8) Value |= 0x40; 50 | if (Transmitter.Count == 0) Value |= 0x80; 51 | return Value; 52 | } 53 | 54 | return 0; 55 | } 56 | 57 | /// 58 | /// Writes a 32-bits value to a Register. 59 | /// 60 | /// The Address being written 61 | /// The value being written 62 | public override void ProcessWrite(uint Address, uint Value) 63 | { 64 | switch (Address) 65 | { 66 | case 0x20201000: 67 | if (Transmitter.Count < 8) 68 | { 69 | Transmitter.Enqueue((byte)Value); 70 | AppendCharacter(); 71 | } 72 | break; 73 | } 74 | } 75 | 76 | /// 77 | /// Appends a character on the console. 78 | /// 79 | private void AppendCharacter() 80 | { 81 | char Character = (char)Transmitter.Dequeue(); 82 | if (OnCharacterReceived != null) OnCharacterReceived(this, new CharacterReceivedEventArgs(Character)); 83 | BufferedOutput += Character; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ChocolateARM/RPi/RPiCore.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading; 3 | 4 | using SharpARM.ARM11; 5 | 6 | namespace ChocolateARM.RPi 7 | { 8 | /// 9 | /// Represents a Raspberry Pi (version 1). 10 | /// 11 | public class RPiCore 12 | { 13 | public ARMCore CPU; 14 | public Memory Memory; 15 | 16 | private bool IsExecuting; 17 | 18 | /// 19 | /// Creates a new instance of the Raspberry Pi emulator. 20 | /// 21 | /// The Picture Box to draw the video output 22 | public RPiCore() 23 | { 24 | Memory = new Memory(); 25 | CPU = new ARMCore(Memory); 26 | } 27 | 28 | /// 29 | /// Loads a binary file into Memory. 30 | /// 31 | /// The full path to the file that should be loaded 32 | /// The Address to place the file into Memory 33 | /// Set the value of PC to the value of Address (where the binary is loaded) 34 | public void Load(string FileName, uint Address, bool SetPC = false) 35 | { 36 | byte[] Buffer = File.ReadAllBytes(FileName); 37 | for (uint i = 0; i < Buffer.Length; i++) 38 | { 39 | Memory.WriteUInt8(Address + i, Buffer[i]); 40 | } 41 | 42 | CPU.Reset(); 43 | if (SetPC) 44 | { 45 | CPU.Registers[15] = Address; 46 | CPU.ReloadPipeline(); 47 | } 48 | } 49 | 50 | /// 51 | /// Executes the program asynchronously until Stop is called. 52 | /// 53 | public void RunAsync() 54 | { 55 | Thread ExecutionThread = new Thread(Run); 56 | ExecutionThread.Start(); 57 | } 58 | 59 | /// 60 | /// Executes instruction on a loop until Stop is called. 61 | /// 62 | private void Run() 63 | { 64 | IsExecuting = true; 65 | while (IsExecuting) CPU.Execute(); 66 | } 67 | 68 | /// 69 | /// Stops executing the instructions. 70 | /// 71 | public void Stop() 72 | { 73 | IsExecuting = false; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ChocolateARM 2 | Bare bones ARM1176 (ARMv6) emulator written in C# 3 | 4 | This is an ARMv6 emulator written in C#, with emulation of some parts of the Raspberry Pi hardware. The CPU was not well tested and probably still contains a lot of bugs. Only a very small portion of the Raspberry Pi hardware was implemented, so it can't run many stuff. Some of the "bare metal" RasPi demos does work. Speed is awfully slow as expected. 5 | You're free to improve or modify any portion of the code, but please give me the credits for what I wrote. Thanks :) 6 | 7 | TODO: 8 | 9 | - More CPU tests are needed 10 | - Implement VFP 11 | - Finish CP15 implementation 12 | - Implement interrupts 13 | - Finish UART 14 | - Add GPIO support and other inputs 15 | --------------------------------------------------------------------------------