├── .gitignore ├── ALU └── ALU.go ├── LICENSE ├── Memory ├── Constants.go ├── DataMemory.go └── InstructionMemory.go ├── README.md ├── arm.go ├── gen_bin.sh └── images ├── demo.gif └── logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | ARMed 2 | testfile* 3 | binaries/ 4 | -------------------------------------------------------------------------------- /ALU/ALU.go: -------------------------------------------------------------------------------- 1 | package ALU 2 | 3 | //Function to perform signed addition of two int64 numbers. 4 | func Adder(val1, val2 int64) int64 { 5 | return val1 + val2 6 | } 7 | 8 | //Function to perform signed multiplication of two int64 numbers. 9 | func Multiplier(val1, val2 int64) int64 { 10 | return val1 * val2 11 | } 12 | 13 | //Function to perform logical AND operation of two int64 numbers. 14 | func LogicalAND(val1, val2 int64) int64 { 15 | return val1 & val2 16 | } 17 | 18 | //Function to perform logical OR operation of two int64 numbers. 19 | func LogicalOR(val1, val2 int64) int64 { 20 | return val1 | val2 21 | } 22 | 23 | //Function to perform logical XOR operation of two int64 numbers. 24 | func LogicalXOR(val1, val2 int64) int64 { 25 | return val1 ^ val2 26 | } 27 | 28 | //Function to perform unsigned addition of two uint64 numbers. 29 | //Used only for setting Carry flag. 30 | func UnsignedAdder(val1, val2 uint64) uint64 { 31 | return val1 + val2 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Deep Bhattacharyya 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Memory/Constants.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | // Program counter increment value 4 | const INCREMENT = 1 5 | 6 | // Data memory size in number of words 7 | const MEMORY_SIZE = 4096 8 | 9 | // Stack size in number of words 10 | const STACK_SIZE = 256 11 | 12 | // Number of bytes in a word 13 | const WORD_SIZE = 4 14 | 15 | // XZR register number 16 | const XZR = 31 17 | 18 | // Stack pointer register number 19 | const SP = 28 20 | 21 | // Link register number 22 | const LR = 30 23 | -------------------------------------------------------------------------------- /Memory/DataMemory.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | "fmt" 5 | color "github.com/fatih/color" 6 | tablewriter "github.com/olekukonko/tablewriter" 7 | "os" 8 | "strconv" 9 | "sync" 10 | ) 11 | 12 | type DataMemory struct { 13 | sync.RWMutex 14 | Memory []int32 15 | } 16 | 17 | var registers, buffer [32]int64 18 | 19 | var flagNegative, flagZero, flagOverflow, flagCarry bool 20 | 21 | // InitRegisters is a function to initiate register values. 22 | func InitRegisters() { 23 | registers[XZR] = 0 24 | registers[SP] = MEMORY_SIZE * 4 25 | } 26 | 27 | // SaveRegisters is a function to store register values in a buffer. 28 | func SaveRegisters() { 29 | var i int 30 | for i = 0; i < 32; i++ { 31 | buffer[i] = registers[i] 32 | } 33 | } 34 | 35 | // ShowRegisters is a function to pretty print register values to terminal. 36 | func ShowRegisters(showAll bool) { 37 | var i int 38 | var hasUpdated bool = false 39 | var registerNum, prevRegisterVal, newRegisterVal string 40 | table := tablewriter.NewWriter(os.Stdout) 41 | if showAll == true { 42 | hasUpdated = true 43 | table.SetHeader([]string{"Register", "Value"}) 44 | 45 | for i = 0; i < 32; i++ { 46 | registerNum = strconv.Itoa(i) 47 | newRegisterVal = strconv.FormatInt(getRegisterValue(uint(i)), 10) 48 | if getRegisterValue(uint(i)) != buffer[i] { 49 | table.Append([]string{color.CyanString("R" + registerNum), color.CyanString(newRegisterVal)}) 50 | } else { 51 | table.Append([]string{"R" + registerNum, newRegisterVal}) 52 | } 53 | } 54 | } else { 55 | table.SetHeader([]string{"Register", "Previous Value", "New Value"}) 56 | 57 | for i = 0; i < 32; i++ { 58 | if getRegisterValue(uint(i)) != buffer[i] { 59 | hasUpdated = true 60 | registerNum = strconv.Itoa(i) 61 | prevRegisterVal = strconv.FormatInt(buffer[i], 10) 62 | newRegisterVal = strconv.FormatInt(getRegisterValue(uint(i)), 10) 63 | table.Append([]string{color.CyanString("R" + registerNum), color.RedString(prevRegisterVal), color.GreenString(newRegisterVal)}) 64 | } 65 | } 66 | } 67 | if hasUpdated { 68 | table.Render() 69 | fmt.Printf("\n") 70 | } 71 | } 72 | 73 | // Method to read data from memory. 74 | // Guarantees mutually exclusive access. 75 | func (dataMemory *DataMemory) read(address uint64) int32 { 76 | dataMemory.RLock() 77 | value := dataMemory.Memory[address] 78 | dataMemory.RUnlock() 79 | return value 80 | } 81 | 82 | // Method to write data to memory. 83 | // Guarantees mutually exclusive access. 84 | func (dataMemory *DataMemory) write(address uint64, value int32) { 85 | dataMemory.Lock() 86 | dataMemory.Memory[address] = value 87 | dataMemory.Unlock() 88 | } 89 | 90 | // Function to read from register and return its value. 91 | func getRegisterValue(registerIndex uint) int64 { 92 | return registers[registerIndex] 93 | } 94 | 95 | // Function to write to register. 96 | func setRegisterValue(registerIndex uint, value int64) { 97 | registers[registerIndex] = value 98 | } 99 | -------------------------------------------------------------------------------- /Memory/InstructionMemory.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | "errors" 5 | ALU "github.com/coderick14/ARMed/ALU" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | // Struct to represent instruction memory 12 | type InstructionMemory struct { 13 | PC int64 14 | Instructions []string 15 | Labels map[string]int64 16 | } 17 | 18 | // Instance of instruction memory 19 | var InstructionMem = InstructionMemory{ 20 | PC: 0, 21 | Instructions: []string{}, 22 | Labels: make(map[string]int64), 23 | } 24 | 25 | // Instance of data memory 26 | var dataMemory = DataMemory{ 27 | Memory: make([]int32, MEMORY_SIZE), 28 | } 29 | 30 | // Method to update program counter. 31 | func (instructionMemory *InstructionMemory) updatePC(offset ...int64) { 32 | if len(offset) == 0 { 33 | instructionMemory.PC += INCREMENT 34 | } else { 35 | instructionMemory.PC += offset[0] 36 | } 37 | } 38 | 39 | // IsValidPC is a function to check if program counter is valid. 40 | func IsValidPC(PC int64) bool { 41 | isValidPC := PC >= 0 && PC < int64(len(InstructionMem.Instructions)) 42 | return isValidPC 43 | } 44 | 45 | // isEmptyInstruction is a method to check for null instructions (NoOps) 46 | func isEmptyInstruction(currentInstruction string) bool { 47 | return len(currentInstruction) == 0 48 | } 49 | 50 | // ExtractLabels is a method to extract labels from instructions. 51 | func (instructionMemory *InstructionMemory) ExtractLabels() { 52 | 53 | labelRegex, _ := regexp.Compile("^([a-zA-Z][[:alnum:]]*)[[:space:]]*:") 54 | for counter, currentInstruction := range instructionMemory.Instructions { 55 | if labelRegex.MatchString(currentInstruction) { 56 | 57 | indexColon := strings.Index(currentInstruction, ":") 58 | labelName := strings.TrimSpace(currentInstruction[:indexColon]) 59 | currentInstruction = strings.TrimSpace(currentInstruction[indexColon+1:]) 60 | instructionMemory.Labels[labelName] = int64(counter) 61 | instructionMemory.Instructions[counter] = currentInstruction 62 | 63 | } 64 | } 65 | } 66 | 67 | // ValidateAndExecuteInstruction is a method to check instruction type, perform syntax analysis, parse the statement and execute it 68 | func (instructionMemory *InstructionMemory) ValidateAndExecuteInstruction() error { 69 | 70 | //get next instruction to be executed from instruction memory 71 | currentInstruction := instructionMemory.Instructions[instructionMemory.PC] 72 | 73 | if isEmptyInstruction(currentInstruction) { 74 | instructionMemory.updatePC() 75 | return nil 76 | } 77 | 78 | var err error 79 | 80 | if strings.HasPrefix(currentInstruction, "ADD ") { 81 | 82 | currentInstructionObject := AddInstruction{inst: currentInstruction} 83 | err = executeInstruction(¤tInstructionObject) 84 | 85 | } else if strings.HasPrefix(currentInstruction, "SUB ") { 86 | 87 | currentInstructionObject := SubInstruction{inst: currentInstruction} 88 | err = executeInstruction(¤tInstructionObject) 89 | 90 | } else if strings.HasPrefix(currentInstruction, "MUL ") { 91 | 92 | currentInstructionObject := MulInstruction{inst: currentInstruction} 93 | err = executeInstruction(¤tInstructionObject) 94 | 95 | } else if strings.HasPrefix(currentInstruction, "ADDI ") { 96 | 97 | currentInstructionObject := AddImmediateInstruction{inst: currentInstruction} 98 | err = executeInstruction(¤tInstructionObject) 99 | 100 | } else if strings.HasPrefix(currentInstruction, "SUBI ") { 101 | 102 | currentInstructionObject := SubImmediateInstruction{inst: currentInstruction} 103 | err = executeInstruction(¤tInstructionObject) 104 | 105 | } else if strings.HasPrefix(currentInstruction, "ADDS ") { 106 | 107 | currentInstructionObject := AddAndSetFlagsInstruction{inst: currentInstruction} 108 | err = executeInstruction(¤tInstructionObject) 109 | 110 | } else if strings.HasPrefix(currentInstruction, "SUBS ") { 111 | 112 | currentInstructionObject := SubAndSetFlagsInstruction{inst: currentInstruction} 113 | err = executeInstruction(¤tInstructionObject) 114 | 115 | } else if strings.HasPrefix(currentInstruction, "ADDIS ") { 116 | 117 | currentInstructionObject := AddImmediateAndSetFlagsInstruction{inst: currentInstruction} 118 | err = executeInstruction(¤tInstructionObject) 119 | 120 | } else if strings.HasPrefix(currentInstruction, "SUBIS ") { 121 | 122 | currentInstructionObject := SubImmediateAndSetFlagsInstruction{inst: currentInstruction} 123 | err = executeInstruction(¤tInstructionObject) 124 | 125 | } else if strings.HasPrefix(currentInstruction, "LDUR ") { 126 | 127 | currentInstructionObject := LoadInstruction{inst: currentInstruction} 128 | err = executeInstruction(¤tInstructionObject) 129 | 130 | } else if strings.HasPrefix(currentInstruction, "STUR ") { 131 | 132 | currentInstructionObject := StoreInstruction{inst: currentInstruction} 133 | err = executeInstruction(¤tInstructionObject) 134 | 135 | } else if strings.HasPrefix(currentInstruction, "LDURH ") { 136 | 137 | currentInstructionObject := LoadHalfInstruction{inst: currentInstruction} 138 | err = executeInstruction(¤tInstructionObject) 139 | 140 | } else if strings.HasPrefix(currentInstruction, "STURH ") { 141 | 142 | currentInstructionObject := StoreHalfInstruction{inst: currentInstruction} 143 | err = executeInstruction(¤tInstructionObject) 144 | 145 | } else if strings.HasPrefix(currentInstruction, "LDURB ") { 146 | 147 | currentInstructionObject := LoadByteInstruction{inst: currentInstruction} 148 | err = executeInstruction(¤tInstructionObject) 149 | 150 | } else if strings.HasPrefix(currentInstruction, "STURB ") { 151 | 152 | currentInstructionObject := StoreByteInstruction{inst: currentInstruction} 153 | err = executeInstruction(¤tInstructionObject) 154 | 155 | } else if strings.HasPrefix(currentInstruction, "MOVZ ") { 156 | 157 | currentInstructionObject := MoveWithZeroInstruction{inst: currentInstruction} 158 | err = executeInstruction(¤tInstructionObject) 159 | 160 | } else if strings.HasPrefix(currentInstruction, "MOVK ") { 161 | 162 | currentInstructionObject := MoveWithKeepInstruction{inst: currentInstruction} 163 | err = executeInstruction(¤tInstructionObject) 164 | 165 | } else if strings.HasPrefix(currentInstruction, "AND ") { 166 | 167 | currentInstructionObject := AndInstruction{inst: currentInstruction} 168 | err = executeInstruction(¤tInstructionObject) 169 | 170 | } else if strings.HasPrefix(currentInstruction, "ORR ") { 171 | 172 | currentInstructionObject := OrInstruction{inst: currentInstruction} 173 | err = executeInstruction(¤tInstructionObject) 174 | 175 | } else if strings.HasPrefix(currentInstruction, "EOR ") { 176 | 177 | currentInstructionObject := ExclusiveOrInstruction{inst: currentInstruction} 178 | err = executeInstruction(¤tInstructionObject) 179 | 180 | } else if strings.HasPrefix(currentInstruction, "ANDI ") { 181 | 182 | currentInstructionObject := AndImmediateInstruction{inst: currentInstruction} 183 | err = executeInstruction(¤tInstructionObject) 184 | 185 | } else if strings.HasPrefix(currentInstruction, "ORRI ") { 186 | 187 | currentInstructionObject := OrImmediateInstruction{inst: currentInstruction} 188 | err = executeInstruction(¤tInstructionObject) 189 | 190 | } else if strings.HasPrefix(currentInstruction, "EORI ") { 191 | 192 | currentInstructionObject := ExclusiveOrImmediateInstruction{inst: currentInstruction} 193 | err = executeInstruction(¤tInstructionObject) 194 | 195 | } else if strings.HasPrefix(currentInstruction, "LSL ") { 196 | 197 | currentInstructionObject := LeftShiftInstruction{inst: currentInstruction} 198 | err = executeInstruction(¤tInstructionObject) 199 | 200 | } else if strings.HasPrefix(currentInstruction, "LSR ") { 201 | 202 | currentInstructionObject := RightShiftInstruction{inst: currentInstruction} 203 | err = executeInstruction(¤tInstructionObject) 204 | 205 | } else if strings.HasPrefix(currentInstruction, "CBZ ") { 206 | 207 | currentInstructionObject := BranchOnZeroInstruction{inst: currentInstruction} 208 | err = executeInstruction(¤tInstructionObject) 209 | 210 | } else if strings.HasPrefix(currentInstruction, "CBNZ ") { 211 | 212 | currentInstructionObject := BranchOnNonZeroInstruction{inst: currentInstruction} 213 | err = executeInstruction(¤tInstructionObject) 214 | 215 | } else if strings.HasPrefix(currentInstruction, "B.") { 216 | 217 | currentInstructionObject := ConditionalBranchInstruction{inst: currentInstruction} 218 | err = executeInstruction(¤tInstructionObject) 219 | 220 | } else if strings.HasPrefix(currentInstruction, "B ") { 221 | 222 | currentInstructionObject := BranchInstruction{inst: currentInstruction} 223 | err = executeInstruction(¤tInstructionObject) 224 | 225 | } else if strings.HasPrefix(currentInstruction, "BR ") { 226 | 227 | currentInstructionObject := BranchToRegisterInstruction{inst: currentInstruction} 228 | err = executeInstruction(¤tInstructionObject) 229 | 230 | } else if strings.HasPrefix(currentInstruction, "BL ") { 231 | 232 | currentInstructionObject := BranchWithLinkInstruction{inst: currentInstruction} 233 | err = executeInstruction(¤tInstructionObject) 234 | 235 | } else { 236 | 237 | err = errors.New("Invalid instruction type in " + currentInstruction) 238 | 239 | } 240 | 241 | return err 242 | } 243 | 244 | // All instructions implement the Instruction interface 245 | type Instruction interface { 246 | // Checks syntax of current instruction and returns an error 247 | checkSyntax() error 248 | 249 | // Parses the current instruction and extracts register numbers, constants etc. 250 | parse() error 251 | 252 | // emulates the execution of the current instruction 253 | execute() 254 | } 255 | 256 | // Function that takes an interface as argument and executes the corresponding instruction 257 | func executeInstruction(currentInstruction Instruction) error { 258 | syntaxError := currentInstruction.checkSyntax() 259 | if syntaxError != nil { 260 | return syntaxError 261 | } else { 262 | parseError := currentInstruction.parse() 263 | if parseError != nil { 264 | return parseError 265 | } 266 | currentInstruction.execute() 267 | } 268 | return nil 269 | } 270 | 271 | /* 272 | INSTRUCTION : ADDITION 273 | 274 | Example : ADD X1, X2, X3 275 | Meaning : X1 = X2 + X3 276 | */ 277 | type AddInstruction struct { 278 | inst string 279 | reg1 uint 280 | reg2 uint 281 | reg3 uint 282 | } 283 | 284 | func (instruction *AddInstruction) checkSyntax() error { 285 | r, _ := regexp.Compile("^ADD X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7])$") 286 | if r.MatchString(instruction.inst) == false { 287 | return errors.New("Syntax error occurred in " + instruction.inst) 288 | } 289 | return nil 290 | } 291 | 292 | func (instruction *AddInstruction) parse() error { 293 | statement := instruction.inst 294 | var registers [3]int 295 | var i, indexX, indexComma int 296 | for i = 0; i < 3; i++ { 297 | indexX = strings.Index(statement, "X") 298 | indexComma = strings.Index(statement, ",") 299 | if indexComma == -1 { 300 | indexComma = len(statement) 301 | } 302 | if statement[indexX+1:indexComma] == "ZR" { 303 | registers[i] = XZR 304 | } else { 305 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 306 | } 307 | if indexComma < len(statement) { 308 | statement = statement[indexComma+1:] 309 | } 310 | } 311 | instruction.reg1 = uint(registers[0]) 312 | instruction.reg2 = uint(registers[1]) 313 | instruction.reg3 = uint(registers[2]) 314 | 315 | return nil 316 | } 317 | 318 | func (instruction *AddInstruction) execute() { 319 | result := ALU.Adder(getRegisterValue(instruction.reg2), getRegisterValue(instruction.reg3)) 320 | setRegisterValue(instruction.reg1, result) 321 | InstructionMem.updatePC() 322 | } 323 | 324 | /* 325 | INSTRUCTION : SUBTRACTION 326 | 327 | Example : SUB X1, X2, X3 328 | Meaning : X1 = X2 - X3 329 | */ 330 | type SubInstruction struct { 331 | inst string 332 | reg1 uint 333 | reg2 uint 334 | reg3 uint 335 | } 336 | 337 | func (instruction *SubInstruction) checkSyntax() error { 338 | r, _ := regexp.Compile("^SUB X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7])$") 339 | if r.MatchString(instruction.inst) == false { 340 | return errors.New("Syntax error occurred in " + instruction.inst) 341 | } 342 | return nil 343 | } 344 | 345 | func (instruction *SubInstruction) parse() error { 346 | statement := instruction.inst 347 | var registers [3]int 348 | var i, indexX, indexComma int 349 | for i = 0; i < 3; i++ { 350 | indexX = strings.Index(statement, "X") 351 | indexComma = strings.Index(statement, ",") 352 | if indexComma == -1 { 353 | indexComma = len(statement) 354 | } 355 | if statement[indexX+1:indexComma] == "ZR" { 356 | registers[i] = XZR 357 | } else { 358 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 359 | } 360 | if indexComma < len(statement) { 361 | statement = statement[indexComma+1:] 362 | } 363 | } 364 | instruction.reg1 = uint(registers[0]) 365 | instruction.reg2 = uint(registers[1]) 366 | instruction.reg3 = uint(registers[2]) 367 | 368 | return nil 369 | } 370 | 371 | func (instruction *SubInstruction) execute() { 372 | result := ALU.Adder(getRegisterValue(instruction.reg2), -getRegisterValue(instruction.reg3)) 373 | setRegisterValue(instruction.reg1, result) 374 | InstructionMem.updatePC() 375 | } 376 | 377 | /* 378 | INSTRUCTION : MULTIPLICATION 379 | 380 | Example : MUL X1, X2, X3 381 | Meaning : X1 = X2 * X3 382 | */ 383 | type MulInstruction struct { 384 | inst string 385 | reg1 uint 386 | reg2 uint 387 | reg3 uint 388 | } 389 | 390 | func (instruction *MulInstruction) checkSyntax() error { 391 | r, _ := regexp.Compile("^MUL X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7])$") 392 | if r.MatchString(instruction.inst) == false { 393 | return errors.New("Syntax error occurred in " + instruction.inst) 394 | } 395 | return nil 396 | } 397 | 398 | func (instruction *MulInstruction) parse() error { 399 | statement := instruction.inst 400 | var registers [3]int 401 | var i, indexX, indexComma int 402 | for i = 0; i < 3; i++ { 403 | indexX = strings.Index(statement, "X") 404 | indexComma = strings.Index(statement, ",") 405 | if indexComma == -1 { 406 | indexComma = len(statement) 407 | } 408 | if statement[indexX+1:indexComma] == "ZR" { 409 | registers[i] = XZR 410 | } else { 411 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 412 | } 413 | if indexComma < len(statement) { 414 | statement = statement[indexComma+1:] 415 | } 416 | } 417 | instruction.reg1 = uint(registers[0]) 418 | instruction.reg2 = uint(registers[1]) 419 | instruction.reg3 = uint(registers[2]) 420 | 421 | return nil 422 | } 423 | 424 | func (instruction *MulInstruction) execute() { 425 | result := ALU.Multiplier(getRegisterValue(instruction.reg2), getRegisterValue(instruction.reg3)) 426 | setRegisterValue(instruction.reg1, result) 427 | InstructionMem.updatePC() 428 | } 429 | 430 | /* 431 | INSTRUCTION : ADD IMMEDIATE 432 | 433 | Example : ADDI X1, X2, 40 434 | Meaning : X1 = X2 + 40 435 | */ 436 | type AddImmediateInstruction struct { 437 | inst string 438 | reg1 uint 439 | reg2 uint 440 | constant uint 441 | } 442 | 443 | func (instruction *AddImmediateInstruction) checkSyntax() error { 444 | r, _ := regexp.Compile("^ADDI ((X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]))|(SP, SP)), #(0|[1-9][0-9]*)$") 445 | if r.MatchString(instruction.inst) == false { 446 | return errors.New("Syntax error occurred in " + instruction.inst) 447 | } 448 | return nil 449 | } 450 | 451 | func (instruction *AddImmediateInstruction) parse() error { 452 | statement := instruction.inst 453 | 454 | // if instruction updates stack pointer 455 | if strings.Index(statement, "SP") != -1 { 456 | indexHash := strings.Index(statement, "#") 457 | constant, _ := strconv.Atoi(statement[indexHash+1:]) 458 | instruction.reg1 = SP 459 | instruction.reg2 = SP 460 | instruction.constant = uint(constant) 461 | 462 | address := getRegisterValue(instruction.reg2) + int64(instruction.constant) 463 | if address > MEMORY_SIZE*WORD_SIZE { 464 | return errors.New("Stack underflow error in : " + instruction.inst) 465 | } 466 | 467 | return nil 468 | } 469 | 470 | var registers [2]int 471 | var i, indexX, indexComma, indexHash int 472 | for i = 0; i < 2; i++ { 473 | indexX = strings.Index(statement, "X") 474 | indexComma = strings.Index(statement, ",") 475 | if statement[indexX+1:indexComma] == "ZR" { 476 | registers[i] = XZR 477 | } else { 478 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 479 | } 480 | statement = statement[indexComma+1:] 481 | } 482 | indexHash = strings.Index(statement, "#") 483 | constant, _ := strconv.Atoi(statement[indexHash+1:]) 484 | 485 | instruction.reg1 = uint(registers[0]) 486 | instruction.reg2 = uint(registers[1]) 487 | instruction.constant = uint(constant) 488 | 489 | return nil 490 | } 491 | 492 | func (instruction *AddImmediateInstruction) execute() { 493 | result := ALU.Adder(getRegisterValue(instruction.reg2), int64(instruction.constant)) 494 | setRegisterValue(instruction.reg1, result) 495 | InstructionMem.updatePC() 496 | } 497 | 498 | /* 499 | INSTRUCTION : SUB IMMEDIATE 500 | 501 | Example : SUBI X1, X2, 40 502 | Meaning : X1 = X2 - 40 503 | */ 504 | type SubImmediateInstruction struct { 505 | inst string 506 | reg1 uint 507 | reg2 uint 508 | constant uint 509 | } 510 | 511 | func (instruction *SubImmediateInstruction) checkSyntax() error { 512 | r, _ := regexp.Compile("^SUBI ((X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]))|(SP, SP)), #(0|[1-9][0-9]*)$") 513 | if r.MatchString(instruction.inst) == false { 514 | return errors.New("Syntax error occurred in " + instruction.inst) 515 | } 516 | return nil 517 | } 518 | 519 | func (instruction *SubImmediateInstruction) parse() error { 520 | statement := instruction.inst 521 | 522 | // if instruction updates stack pointer 523 | if strings.Index(statement, "SP") != -1 { 524 | indexHash := strings.Index(statement, "#") 525 | constant, _ := strconv.Atoi(statement[indexHash+1:]) 526 | instruction.reg1 = SP 527 | instruction.reg2 = SP 528 | instruction.constant = uint(constant) 529 | 530 | address := getRegisterValue(instruction.reg2) + int64(instruction.constant) 531 | if address < (MEMORY_SIZE-STACK_SIZE)*WORD_SIZE { 532 | return errors.New("Stack overflow error in : " + instruction.inst) 533 | } 534 | 535 | return nil 536 | } 537 | 538 | var registers [2]int 539 | var i, indexX, indexComma, indexHash int 540 | for i = 0; i < 2; i++ { 541 | indexX = strings.Index(statement, "X") 542 | indexComma = strings.Index(statement, ",") 543 | if statement[indexX+1:indexComma] == "ZR" { 544 | registers[i] = XZR 545 | } else { 546 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 547 | } 548 | statement = statement[indexComma+1:] 549 | } 550 | indexHash = strings.Index(statement, "#") 551 | constant, _ := strconv.Atoi(statement[indexHash+1:]) 552 | 553 | instruction.reg1 = uint(registers[0]) 554 | instruction.reg2 = uint(registers[1]) 555 | instruction.constant = uint(constant) 556 | 557 | return nil 558 | } 559 | 560 | func (instruction *SubImmediateInstruction) execute() { 561 | result := ALU.Adder(getRegisterValue(instruction.reg2), -int64(instruction.constant)) 562 | setRegisterValue(instruction.reg1, result) 563 | InstructionMem.updatePC() 564 | } 565 | 566 | /* 567 | INSTRUCTION : ADD AND SET FLAGS 568 | 569 | Example : ADDS X1, X2, X3 570 | Meaning : X1 = X2 + X3 571 | 572 | Comments : Adds and sets condition codes 573 | */ 574 | type AddAndSetFlagsInstruction struct { 575 | inst string 576 | reg1 uint 577 | reg2 uint 578 | reg3 uint 579 | } 580 | 581 | func (instruction *AddAndSetFlagsInstruction) checkSyntax() error { 582 | r, _ := regexp.Compile("^ADDS X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7])$") 583 | if r.MatchString(instruction.inst) == false { 584 | return errors.New("Syntax error occurred in " + instruction.inst) 585 | } 586 | return nil 587 | } 588 | 589 | func (instruction *AddAndSetFlagsInstruction) parse() error { 590 | statement := instruction.inst 591 | var registers [3]int 592 | var i, indexX, indexComma int 593 | for i = 0; i < 3; i++ { 594 | indexX = strings.Index(statement, "X") 595 | indexComma = strings.Index(statement, ",") 596 | if indexComma == -1 { 597 | indexComma = len(statement) 598 | } 599 | if statement[indexX+1:indexComma] == "ZR" { 600 | registers[i] = XZR 601 | } else { 602 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 603 | } 604 | if indexComma < len(statement) { 605 | statement = statement[indexComma+1:] 606 | } 607 | } 608 | instruction.reg1 = uint(registers[0]) 609 | instruction.reg2 = uint(registers[1]) 610 | instruction.reg3 = uint(registers[2]) 611 | 612 | return nil 613 | } 614 | 615 | func (instruction *AddAndSetFlagsInstruction) execute() { 616 | result := ALU.Adder(getRegisterValue(instruction.reg2), getRegisterValue(instruction.reg3)) 617 | setRegisterValue(instruction.reg1, result) 618 | 619 | //set flag N 620 | if result < 0 { 621 | flagNegative = true 622 | } else { 623 | flagNegative = false 624 | } 625 | 626 | //set flag Z 627 | if result == 0 { 628 | flagZero = true 629 | } else { 630 | flagZero = false 631 | } 632 | 633 | var hasOverflowOccured bool 634 | 635 | //set flag V (signed addition overflow) 636 | hasOverflowOccured = (getRegisterValue(instruction.reg2) > 0 && getRegisterValue(instruction.reg3) > 0 && result >= int64(1<<31)) || (getRegisterValue(instruction.reg2) < 0 && getRegisterValue(instruction.reg3) < 0 && result < -int64(1<<31)) 637 | if hasOverflowOccured { 638 | flagOverflow = true 639 | } else { 640 | flagOverflow = false 641 | } 642 | 643 | //set flag C (unsigned addition overflow) 644 | unsignedSum := ALU.UnsignedAdder(uint64(getRegisterValue(instruction.reg2)), uint64(getRegisterValue(instruction.reg3))) 645 | if unsignedSum >= uint64(1<<32) { 646 | flagCarry = true 647 | } else { 648 | flagCarry = false 649 | } 650 | 651 | InstructionMem.updatePC() 652 | } 653 | 654 | /* 655 | INSTRUCTION : SUB AND SET FLAGS 656 | 657 | Example : SUBS X1, X2, X3 658 | Meaning : X1 = X2 - X3 659 | 660 | Comments : Subtracts and sets condition codes 661 | */ 662 | type SubAndSetFlagsInstruction struct { 663 | inst string 664 | reg1 uint 665 | reg2 uint 666 | reg3 uint 667 | } 668 | 669 | func (instruction *SubAndSetFlagsInstruction) checkSyntax() error { 670 | r, _ := regexp.Compile("^SUBS X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7])$") 671 | if r.MatchString(instruction.inst) == false { 672 | return errors.New("Syntax error occurred in " + instruction.inst) 673 | } 674 | return nil 675 | } 676 | 677 | func (instruction *SubAndSetFlagsInstruction) parse() error { 678 | statement := instruction.inst 679 | var registers [3]int 680 | var i, indexX, indexComma int 681 | for i = 0; i < 3; i++ { 682 | indexX = strings.Index(statement, "X") 683 | indexComma = strings.Index(statement, ",") 684 | if indexComma == -1 { 685 | indexComma = len(statement) 686 | } 687 | if statement[indexX+1:indexComma] == "ZR" { 688 | registers[i] = XZR 689 | } else { 690 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 691 | } 692 | if indexComma < len(statement) { 693 | statement = statement[indexComma+1:] 694 | } 695 | } 696 | instruction.reg1 = uint(registers[0]) 697 | instruction.reg2 = uint(registers[1]) 698 | instruction.reg3 = uint(registers[2]) 699 | 700 | return nil 701 | } 702 | 703 | func (instruction *SubAndSetFlagsInstruction) execute() { 704 | result := ALU.Adder(getRegisterValue(instruction.reg2), getRegisterValue(instruction.reg3)) 705 | setRegisterValue(instruction.reg1, result) 706 | 707 | //set flag N 708 | if result < 0 { 709 | flagNegative = true 710 | } else { 711 | flagNegative = false 712 | } 713 | 714 | //set flag Z 715 | if result == 0 { 716 | flagZero = true 717 | } else { 718 | flagZero = false 719 | } 720 | 721 | var hasOverflowOccured bool 722 | 723 | //set flag V (signed addition overflow) 724 | hasOverflowOccured = (getRegisterValue(instruction.reg2) > 0 && getRegisterValue(instruction.reg3) < 0 && result >= int64(1<<31)) || (getRegisterValue(instruction.reg2) < 0 && getRegisterValue(instruction.reg3) > 0 && result < -int64(1<<31)) 725 | if hasOverflowOccured { 726 | flagOverflow = true 727 | } else { 728 | flagOverflow = false 729 | } 730 | 731 | //set flag C (unsigned addition overflow) 732 | if uint64(getRegisterValue(instruction.reg2)) < uint64(getRegisterValue(instruction.reg3)) { 733 | flagCarry = true 734 | } else { 735 | flagCarry = false 736 | } 737 | 738 | InstructionMem.updatePC() 739 | } 740 | 741 | /* 742 | INSTRUCTION : ADD IMMEDIATE AND SET FLAGS 743 | 744 | Example : ADDIS X1, X2, 40 745 | Meaning : X1 = X2 + 40 746 | 747 | Comments : Adds constant and sets condition codes 748 | */ 749 | type AddImmediateAndSetFlagsInstruction struct { 750 | inst string 751 | reg1 uint 752 | reg2 uint 753 | constant uint 754 | } 755 | 756 | func (instruction *AddImmediateAndSetFlagsInstruction) checkSyntax() error { 757 | r, _ := regexp.Compile("^ADDIS X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]), #(0|[1-9][0-9]*)$") 758 | if r.MatchString(instruction.inst) == false { 759 | return errors.New("Syntax error occurred in " + instruction.inst) 760 | } 761 | return nil 762 | } 763 | 764 | func (instruction *AddImmediateAndSetFlagsInstruction) parse() error { 765 | statement := instruction.inst 766 | var registers [2]int 767 | var i, indexX, indexComma, indexHash int 768 | for i = 0; i < 2; i++ { 769 | indexX = strings.Index(statement, "X") 770 | indexComma = strings.Index(statement, ",") 771 | if statement[indexX+1:indexComma] == "ZR" { 772 | registers[i] = 31 773 | } else { 774 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 775 | } 776 | statement = statement[indexComma+1:] 777 | } 778 | indexHash = strings.Index(statement, "#") 779 | constant, _ := strconv.Atoi(statement[indexHash+1:]) 780 | 781 | instruction.reg1 = uint(registers[0]) 782 | instruction.reg2 = uint(registers[1]) 783 | instruction.constant = uint(constant) 784 | 785 | return nil 786 | } 787 | 788 | func (instruction *AddImmediateAndSetFlagsInstruction) execute() { 789 | result := ALU.Adder(getRegisterValue(instruction.reg2), int64(instruction.constant)) 790 | setRegisterValue(instruction.reg1, result) 791 | 792 | //set flag N 793 | if result < 0 { 794 | flagNegative = true 795 | } else { 796 | flagNegative = false 797 | } 798 | 799 | //set flag Z 800 | if result == 0 { 801 | flagZero = true 802 | } else { 803 | flagZero = false 804 | } 805 | 806 | var hasOverflowOccured bool 807 | 808 | //set flag V (signed addition overflow) 809 | hasOverflowOccured = (getRegisterValue(instruction.reg2) > 0 && result >= int64(1<<31)) 810 | if hasOverflowOccured { 811 | flagOverflow = true 812 | } else { 813 | flagOverflow = false 814 | } 815 | 816 | //set flag C (unsigned addition overflow) 817 | unsignedSum := ALU.UnsignedAdder(uint64(getRegisterValue(instruction.reg2)), uint64(instruction.constant)) 818 | if unsignedSum >= uint64(1<<32) { 819 | flagCarry = true 820 | } else { 821 | flagCarry = false 822 | } 823 | 824 | InstructionMem.updatePC() 825 | } 826 | 827 | /* 828 | INSTRUCTION : SUB IMMEDIATE AND SET FLAGS 829 | 830 | Example : SUBIS X1, X2, 40 831 | Meaning : X1 = X2 - 40 832 | 833 | Comments : Subtracts constant and sets condition codes 834 | */ 835 | type SubImmediateAndSetFlagsInstruction struct { 836 | inst string 837 | reg1 uint 838 | reg2 uint 839 | constant uint 840 | } 841 | 842 | func (instruction *SubImmediateAndSetFlagsInstruction) checkSyntax() error { 843 | r, _ := regexp.Compile("^SUBIS X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]), #(0|[1-9][0-9]*)$") 844 | if r.MatchString(instruction.inst) == false { 845 | return errors.New("Syntax error occurred in " + instruction.inst) 846 | } 847 | return nil 848 | } 849 | 850 | func (instruction *SubImmediateAndSetFlagsInstruction) parse() error { 851 | statement := instruction.inst 852 | var registers [2]int 853 | var i, indexX, indexComma, indexHash int 854 | for i = 0; i < 2; i++ { 855 | indexX = strings.Index(statement, "X") 856 | indexComma = strings.Index(statement, ",") 857 | if statement[indexX+1:indexComma] == "ZR" { 858 | registers[i] = 31 859 | } else { 860 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 861 | } 862 | statement = statement[indexComma+1:] 863 | } 864 | indexHash = strings.Index(statement, "#") 865 | constant, _ := strconv.Atoi(statement[indexHash+1:]) 866 | 867 | instruction.reg1 = uint(registers[0]) 868 | instruction.reg2 = uint(registers[1]) 869 | instruction.constant = uint(constant) 870 | 871 | return nil 872 | } 873 | 874 | func (instruction *SubImmediateAndSetFlagsInstruction) execute() { 875 | result := ALU.Adder(getRegisterValue(instruction.reg2), -int64(instruction.constant)) 876 | setRegisterValue(instruction.reg1, result) 877 | 878 | //set flag N 879 | if result < 0 { 880 | flagNegative = true 881 | } else { 882 | flagNegative = false 883 | } 884 | 885 | //set flag Z 886 | if result == 0 { 887 | flagZero = true 888 | } else { 889 | flagZero = false 890 | } 891 | 892 | var hasOverflowOccured bool 893 | 894 | //set flag V (signed addition overflow) 895 | hasOverflowOccured = (getRegisterValue(instruction.reg2) < 0 && result < -int64(1<<31)) 896 | if hasOverflowOccured { 897 | flagOverflow = true 898 | } else { 899 | flagOverflow = false 900 | } 901 | 902 | //set flag C (unsigned addition overflow) 903 | if uint64(getRegisterValue(instruction.reg2)) < uint64(instruction.constant) { 904 | flagCarry = true 905 | } else { 906 | flagCarry = false 907 | } 908 | 909 | InstructionMem.updatePC() 910 | } 911 | 912 | /* 913 | INSTRUCTION : LOAD 914 | 915 | Example : LDUR X1, [X2, #40] 916 | Meaning : X1 = Memory[X2 + 40] 917 | 918 | Comments : Word from memory to register 919 | */ 920 | type LoadInstruction struct { 921 | inst string 922 | reg1 uint 923 | reg2 uint 924 | offset uint 925 | } 926 | 927 | func (instruction *LoadInstruction) checkSyntax() error { 928 | r, _ := regexp.Compile("^LDUR (X([0-9]|1[0-9]|2[0-7])|LR), \\[(X([0-9]|1[0-9]|2[0-7])|SP), #(0|[1-9][0-9]*)\\]$") 929 | if r.MatchString(instruction.inst) == false { 930 | return errors.New("Syntax error occurred in " + instruction.inst) 931 | } 932 | return nil 933 | } 934 | 935 | func (instruction *LoadInstruction) parse() error { 936 | statement := instruction.inst 937 | var registers [2]int 938 | var i, indexX, indexLR, indexComma, indexHash, indexBracket, offset int 939 | for i = 0; i < 2; i++ { 940 | indexX = strings.Index(statement, "X") 941 | indexLR = strings.Index(statement, "LR") 942 | indexComma = strings.Index(statement, ",") 943 | if indexX != -1 { 944 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 945 | } else if indexLR != -1 { 946 | registers[i] = LR 947 | } else { 948 | registers[i] = SP 949 | } 950 | statement = statement[indexComma+1:] 951 | } 952 | indexHash = strings.Index(statement, "#") 953 | indexBracket = strings.Index(statement, "]") 954 | offset, _ = strconv.Atoi(statement[indexHash+1 : indexBracket]) 955 | 956 | instruction.reg1 = uint(registers[0]) 957 | instruction.reg2 = uint(registers[1]) 958 | instruction.offset = uint(offset) 959 | 960 | //check for alignment restriction 961 | if (getRegisterValue(instruction.reg2)+int64(instruction.offset))%4 != 0 { 962 | return errors.New("Alignment restriction violation in : " + instruction.inst) 963 | } 964 | 965 | return nil 966 | } 967 | 968 | func (instruction *LoadInstruction) execute() { 969 | memoryIndex := ALU.Adder(getRegisterValue(instruction.reg2), int64(instruction.offset)) / 4 970 | memoryValue := dataMemory.read(uint64(memoryIndex)) 971 | setRegisterValue(instruction.reg1, int64(memoryValue)) 972 | InstructionMem.updatePC() 973 | } 974 | 975 | /* 976 | INSTRUCTION : STORE 977 | 978 | Example : STUR X1, [X2, #40] 979 | Meaning : Memory[X2 + 40] = X1 980 | 981 | Comments : Word from register to memory 982 | */ 983 | type StoreInstruction struct { 984 | inst string 985 | reg1 uint 986 | reg2 uint 987 | offset uint 988 | } 989 | 990 | func (instruction *StoreInstruction) checkSyntax() error { 991 | r, _ := regexp.Compile("^STUR (X([0-9]|1[0-9]|2[0-7])|LR), \\[(X([0-9]|1[0-9]|2[0-7])|SP), #(0|[1-9][0-9]*)\\]$") 992 | if r.MatchString(instruction.inst) == false { 993 | return errors.New("Syntax error occurred in " + instruction.inst) 994 | } 995 | return nil 996 | } 997 | 998 | func (instruction *StoreInstruction) parse() error { 999 | statement := instruction.inst 1000 | var registers [2]int 1001 | var i, indexX, indexLR, indexComma, indexHash, indexBracket, offset int 1002 | for i = 0; i < 2; i++ { 1003 | indexX = strings.Index(statement, "X") 1004 | indexLR = strings.Index(statement, "LR") 1005 | indexComma = strings.Index(statement, ",") 1006 | if indexX != -1 { 1007 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 1008 | } else if indexLR != -1 { 1009 | registers[i] = LR 1010 | } else { 1011 | registers[i] = SP 1012 | } 1013 | statement = statement[indexComma+1:] 1014 | } 1015 | indexHash = strings.Index(statement, "#") 1016 | indexBracket = strings.Index(statement, "]") 1017 | offset, _ = strconv.Atoi(statement[indexHash+1 : indexBracket]) 1018 | 1019 | instruction.reg1 = uint(registers[0]) 1020 | instruction.reg2 = uint(registers[1]) 1021 | instruction.offset = uint(offset) 1022 | 1023 | //check for alignment restriction 1024 | if (getRegisterValue(instruction.reg2)+int64(instruction.offset))%4 != 0 { 1025 | return errors.New("Alignment restriction violation in : " + instruction.inst) 1026 | } 1027 | 1028 | return nil 1029 | } 1030 | 1031 | func (instruction *StoreInstruction) execute() { 1032 | memoryIndex := ALU.Adder(getRegisterValue(instruction.reg2), int64(instruction.offset)) / 4 1033 | registerValue := getRegisterValue(instruction.reg1) 1034 | dataMemory.write(uint64(memoryIndex), int32(registerValue)) 1035 | InstructionMem.updatePC() 1036 | } 1037 | 1038 | /* 1039 | INSTRUCTION : LOAD HALFWORD 1040 | 1041 | Example : LDURH X1, [X2, #40] 1042 | Meaning : X1 = Memory[X2 + 40] 1043 | 1044 | Comments : Halfword from memory to register 1045 | */ 1046 | type LoadHalfInstruction struct { 1047 | inst string 1048 | reg1 uint 1049 | reg2 uint 1050 | offset uint 1051 | } 1052 | 1053 | func (instruction *LoadHalfInstruction) checkSyntax() error { 1054 | r, _ := regexp.Compile("^LDURH X([0-9]|1[0-9]|2[0-7]), \\[X([0-9]|1[0-9]|2[0-7]), #(0|[1-9][0-9]*)\\]$") 1055 | if r.MatchString(instruction.inst) == false { 1056 | return errors.New("Syntax error occurred in " + instruction.inst) 1057 | } 1058 | return nil 1059 | } 1060 | 1061 | func (instruction *LoadHalfInstruction) parse() error { 1062 | statement := instruction.inst 1063 | var registers [2]int 1064 | var i, indexX, indexComma, indexHash, indexBracket, offset int 1065 | for i = 0; i < 2; i++ { 1066 | indexX = strings.Index(statement, "X") 1067 | indexComma = strings.Index(statement, ",") 1068 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 1069 | statement = statement[indexComma+1:] 1070 | } 1071 | indexHash = strings.Index(statement, "#") 1072 | indexBracket = strings.Index(statement, "]") 1073 | offset, _ = strconv.Atoi(statement[indexHash+1 : indexBracket]) 1074 | 1075 | instruction.reg1 = uint(registers[0]) 1076 | instruction.reg2 = uint(registers[1]) 1077 | instruction.offset = uint(offset) 1078 | 1079 | //check for alignment restriction 1080 | if (getRegisterValue(instruction.reg2)+int64(instruction.offset))%4 != 0 && (getRegisterValue(instruction.reg2)+int64(instruction.offset))%4 != 2 { 1081 | return errors.New("Alignment restriction violation in : " + instruction.inst) 1082 | } 1083 | 1084 | return nil 1085 | } 1086 | 1087 | func (instruction *LoadHalfInstruction) execute() { 1088 | var memoryValue int16 1089 | var shift uint = 16 1090 | memoryIndex := ALU.Adder(getRegisterValue(instruction.reg2), int64(instruction.offset)) 1091 | if memoryIndex%4 == 0 { 1092 | // extract upper 16 bits 1093 | memoryValue = int16(dataMemory.read(uint64(memoryIndex/4)) >> shift) 1094 | } else { 1095 | // extract lower 16 bits 1096 | memoryValue = int16(dataMemory.read(uint64(memoryIndex / 4))) 1097 | } 1098 | setRegisterValue(instruction.reg1, int64(memoryValue)) 1099 | 1100 | InstructionMem.updatePC() 1101 | } 1102 | 1103 | /* 1104 | INSTRUCTION : STORE HALFWORD 1105 | 1106 | Example : STURH X1, [X2, #40] 1107 | Meaning : Memory[X2 + 40] = X1 1108 | 1109 | Comments : Halfword from register to memory 1110 | */ 1111 | type StoreHalfInstruction struct { 1112 | inst string 1113 | reg1 uint 1114 | reg2 uint 1115 | offset uint 1116 | } 1117 | 1118 | func (instruction *StoreHalfInstruction) checkSyntax() error { 1119 | r, _ := regexp.Compile("^STURH X([0-9]|1[0-9]|2[0-7]), \\[X([0-9]|1[0-9]|2[0-7]), #(0|[1-9][0-9]*)\\]$") 1120 | if r.MatchString(instruction.inst) == false { 1121 | return errors.New("Syntax error occurred in " + instruction.inst) 1122 | } 1123 | return nil 1124 | } 1125 | 1126 | func (instruction *StoreHalfInstruction) parse() error { 1127 | statement := instruction.inst 1128 | var registers [2]int 1129 | var i, indexX, indexComma, indexHash, indexBracket, offset int 1130 | for i = 0; i < 2; i++ { 1131 | indexX = strings.Index(statement, "X") 1132 | indexComma = strings.Index(statement, ",") 1133 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 1134 | statement = statement[indexComma+1:] 1135 | } 1136 | indexHash = strings.Index(statement, "#") 1137 | indexBracket = strings.Index(statement, "]") 1138 | offset, _ = strconv.Atoi(statement[indexHash+1 : indexBracket]) 1139 | 1140 | instruction.reg1 = uint(registers[0]) 1141 | instruction.reg2 = uint(registers[1]) 1142 | instruction.offset = uint(offset) 1143 | 1144 | //check for alignment restriction 1145 | if (getRegisterValue(instruction.reg2)+int64(instruction.offset))%4 != 0 && (getRegisterValue(instruction.reg2)+int64(instruction.offset))%4 != 2 { 1146 | return errors.New("Alignment restriction violation in : " + instruction.inst) 1147 | } 1148 | 1149 | return nil 1150 | } 1151 | 1152 | func (instruction *StoreHalfInstruction) execute() { 1153 | var registerValue int16 1154 | var shift uint = 16 1155 | registerValue = int16(getRegisterValue(instruction.reg1)) 1156 | memoryIndex := ALU.Adder(getRegisterValue(instruction.reg2), int64(instruction.offset)) 1157 | currentMemoryValue := dataMemory.read(uint64(memoryIndex / 4)) 1158 | if memoryIndex%4 == 0 { 1159 | // store in upper 16 bits 1160 | currentMemoryValue = currentMemoryValue & ((1 << shift) - 1) // clear upper 16 bits 1161 | currentMemoryValue = currentMemoryValue | (int32(registerValue) << shift) 1162 | } else { 1163 | // store in lower 16 bits 1164 | currentMemoryValue = currentMemoryValue & -(1 << shift) // clear lower 16 bits 1165 | currentMemoryValue = currentMemoryValue | int32(registerValue) 1166 | } 1167 | dataMemory.write(uint64(memoryIndex/4), currentMemoryValue) 1168 | 1169 | InstructionMem.updatePC() 1170 | } 1171 | 1172 | /* 1173 | INSTRUCTION : LOAD BYTE 1174 | 1175 | Example : LDURB X1, [X2, #40] 1176 | Meaning : X1 = Memory[X2 + 40] 1177 | 1178 | Comments : Byte from memory to register 1179 | */ 1180 | type LoadByteInstruction struct { 1181 | inst string 1182 | reg1 uint 1183 | reg2 uint 1184 | offset uint 1185 | } 1186 | 1187 | func (instruction *LoadByteInstruction) checkSyntax() error { 1188 | r, _ := regexp.Compile("^LDURB X([0-9]|1[0-9]|2[0-7]), \\[X([0-9]|1[0-9]|2[0-7]), #(0|[1-9][0-9]*)\\]$") 1189 | if r.MatchString(instruction.inst) == false { 1190 | return errors.New("Syntax error occurred in " + instruction.inst) 1191 | } 1192 | return nil 1193 | } 1194 | 1195 | func (instruction *LoadByteInstruction) parse() error { 1196 | statement := instruction.inst 1197 | var registers [2]int 1198 | var i, indexX, indexComma, indexHash, indexBracket, offset int 1199 | for i = 0; i < 2; i++ { 1200 | indexX = strings.Index(statement, "X") 1201 | indexComma = strings.Index(statement, ",") 1202 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 1203 | statement = statement[indexComma+1:] 1204 | } 1205 | indexHash = strings.Index(statement, "#") 1206 | indexBracket = strings.Index(statement, "]") 1207 | offset, _ = strconv.Atoi(statement[indexHash+1 : indexBracket]) 1208 | 1209 | instruction.reg1 = uint(registers[0]) 1210 | instruction.reg2 = uint(registers[1]) 1211 | instruction.offset = uint(offset) 1212 | 1213 | return nil 1214 | } 1215 | 1216 | func (instruction *LoadByteInstruction) execute() { 1217 | var registerValue int8 1218 | memoryIndex := ALU.Adder(getRegisterValue(instruction.reg2), int64(instruction.offset)) 1219 | memoryValue := dataMemory.read(uint64(memoryIndex / 4)) 1220 | if memoryIndex%4 == 0 { 1221 | // extract bits[31:24] 1222 | registerValue = int8(memoryValue >> 24) 1223 | } else if memoryIndex%4 == 1 { 1224 | // extract bits[23:16] 1225 | registerValue = int8(memoryValue >> 16) 1226 | } else if memoryIndex%4 == 2 { 1227 | // extract bits[15:8] 1228 | registerValue = int8(memoryValue >> 8) 1229 | } else { 1230 | // extract bit[7:0] 1231 | registerValue = int8(memoryValue) 1232 | } 1233 | setRegisterValue(instruction.reg1, int64(registerValue)) 1234 | 1235 | InstructionMem.updatePC() 1236 | } 1237 | 1238 | /* 1239 | INSTRUCTION : STORE BYTE 1240 | 1241 | Example : STURB X1, [X2, #40] 1242 | Meaning : Memory[X2 + 40] = X1 1243 | 1244 | Comments : Byte from register to memory 1245 | */ 1246 | type StoreByteInstruction struct { 1247 | inst string 1248 | reg1 uint 1249 | reg2 uint 1250 | offset uint 1251 | } 1252 | 1253 | func (instruction *StoreByteInstruction) checkSyntax() error { 1254 | r, _ := regexp.Compile("^STURB X([0-9]|1[0-9]|2[0-7]), \\[X([0-9]|1[0-9]|2[0-7]), #(0|[1-9][0-9]*)\\]$") 1255 | if r.MatchString(instruction.inst) == false { 1256 | return errors.New("Syntax error occurred in " + instruction.inst) 1257 | } 1258 | return nil 1259 | } 1260 | 1261 | func (instruction *StoreByteInstruction) parse() error { 1262 | statement := instruction.inst 1263 | var registers [2]int 1264 | var i, indexX, indexComma, indexHash, indexBracket, offset int 1265 | for i = 0; i < 2; i++ { 1266 | indexX = strings.Index(statement, "X") 1267 | indexComma = strings.Index(statement, ",") 1268 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 1269 | statement = statement[indexComma+1:] 1270 | } 1271 | indexHash = strings.Index(statement, "#") 1272 | indexBracket = strings.Index(statement, "]") 1273 | offset, _ = strconv.Atoi(statement[indexHash+1 : indexBracket]) 1274 | 1275 | instruction.reg1 = uint(registers[0]) 1276 | instruction.reg2 = uint(registers[1]) 1277 | instruction.offset = uint(offset) 1278 | 1279 | return nil 1280 | } 1281 | 1282 | func (instruction *StoreByteInstruction) execute() { 1283 | var registerValue int8 1284 | registerValue = int8(getRegisterValue(instruction.reg1)) 1285 | memoryIndex := ALU.Adder(getRegisterValue(instruction.reg2), int64(instruction.offset)) 1286 | currentMemoryValue := dataMemory.read(uint64(memoryIndex / 4)) 1287 | if memoryIndex%4 == 0 { 1288 | 1289 | // store in bits[31:24] 1290 | currentMemoryValue = currentMemoryValue & ((1 << 24) - 1) // clear bits[31:24] 1291 | currentMemoryValue = currentMemoryValue | (int32(registerValue) << 24) 1292 | 1293 | } else if memoryIndex%4 == 1 { 1294 | 1295 | // store in bits[23:16] 1296 | currentMemoryValue = currentMemoryValue & (((1 << 16) - 1) | -(1 << 24)) // clear bits[23:16] 1297 | currentMemoryValue = currentMemoryValue | (int32(registerValue) << 16) 1298 | 1299 | } else if memoryIndex%4 == 2 { 1300 | 1301 | // store in bits[15:8] 1302 | currentMemoryValue = currentMemoryValue & (((1 << 8) - 1) | -(1 << 16)) // clear bits[15:8] 1303 | currentMemoryValue = currentMemoryValue | (int32(registerValue) << 8) 1304 | 1305 | } else { 1306 | 1307 | // store in bits[7:0] 1308 | currentMemoryValue = currentMemoryValue & -(1 << 8) // clear bits[7:0] 1309 | currentMemoryValue = currentMemoryValue | int32(registerValue) 1310 | 1311 | } 1312 | dataMemory.write(uint64(memoryIndex/4), currentMemoryValue) 1313 | 1314 | InstructionMem.updatePC() 1315 | } 1316 | 1317 | /* 1318 | INSTRUCTION : LOAD EXCLUSIVE REGISTER 1319 | 1320 | Example : LDXR X1, [X2, #0] 1321 | Meaning : X1 = Memory[X2] 1322 | 1323 | Comments : Load; first half of atomic swap 1324 | */ 1325 | // type LoadExclusiveInstruction struct { 1326 | // inst string 1327 | // reg1 uint 1328 | // reg2 uint 1329 | // } 1330 | 1331 | // func (instruction *LoadExclusiveInstruction) checkSyntax() error { 1332 | // r, _ := regexp.Compile("^LDXR X([0-9]|1[0-9]|2[0-7]), \\[X(ZR|[0-9]|1[0-9]|2[0-7]), #(0|[1-9][0-9]*)\\]$") 1333 | // if r.MatchString(instruction.inst) == false { 1334 | // return errors.New("Syntax error occurred in " + instruction.inst) 1335 | // } 1336 | // return nil 1337 | // } 1338 | 1339 | // func (instruction *LoadExclusiveInstruction) parse() error { 1340 | 1341 | // return nil 1342 | // } 1343 | 1344 | // func (instruction *LoadExclusiveInstruction) execute() { 1345 | 1346 | // } 1347 | 1348 | /* 1349 | INSTRUCTION : STORE EXCLUSIVE REGISTER 1350 | 1351 | Example : STXR X1, X3, [X2, #0] 1352 | Meaning : Memory[X2] = X1; X3 = 0 or 1 1353 | 1354 | Comments : Store; second half of atomic swap 1355 | */ 1356 | // type StoreExclusiveInstruction struct { 1357 | // inst string 1358 | // reg1 uint 1359 | // reg2 uint 1360 | // reg3 uint 1361 | // } 1362 | 1363 | // func (instruction *StoreExclusiveInstruction) checkSyntax() error { 1364 | // r, _ := regexp.Compile("^STXR X([0-9]|1[0-9]|2[0-7]), X([0-9]|1[0-9]|2[0-7]), \\[X(ZR|[0-9]|1[0-9]|2[0-7]), #(0|[1-9][0-9]*)\\]$") 1365 | // if r.MatchString(instruction.inst) == false { 1366 | // return errors.New("Syntax error occurred in " + instruction.inst) 1367 | // } 1368 | // return nil 1369 | // } 1370 | 1371 | // func (instruction *StoreExclusiveInstruction) parse() error { 1372 | 1373 | // return nil 1374 | // } 1375 | 1376 | // func (instruction *StoreExclusiveInstruction) execute() { 1377 | 1378 | // } 1379 | 1380 | /* 1381 | INSTRUCTION : MOVE WITH ZERO 1382 | 1383 | Example : MOVZ X1, 20, LSL 0 1384 | Meaning : X1 = 20 or 20*(2^16) or 20*(2^32) or 20*(2^48) 1385 | 1386 | Comments : Loads 16-bit constant, rest zeroes 1387 | */ 1388 | type MoveWithZeroInstruction struct { 1389 | inst string 1390 | reg1 uint 1391 | constant uint16 1392 | offset uint 1393 | } 1394 | 1395 | func (instruction *MoveWithZeroInstruction) checkSyntax() error { 1396 | r, _ := regexp.Compile("^MOVZ X([0-9]|1[0-9]|2[0-7]), (0|[1-9][0-9]*), LSL (0|1|2|3)$") 1397 | if r.MatchString(instruction.inst) == false { 1398 | return errors.New("Syntax error occurred in " + instruction.inst) 1399 | } 1400 | return nil 1401 | } 1402 | 1403 | func (instruction *MoveWithZeroInstruction) parse() error { 1404 | statement := instruction.inst 1405 | var indexX, indexComma int 1406 | 1407 | indexX = strings.Index(statement, "X") 1408 | indexComma = strings.Index(statement, ",") 1409 | register, _ := strconv.Atoi(statement[indexX+1 : indexComma]) 1410 | 1411 | statement = strings.TrimSpace(statement[indexComma+1:]) 1412 | indexComma = strings.Index(statement, ",") 1413 | constant, _ := strconv.Atoi(statement[:indexComma]) 1414 | 1415 | offset := uint(statement[len(statement)-1] - '0') 1416 | 1417 | instruction.reg1 = uint(register) 1418 | instruction.constant = uint16(constant) 1419 | instruction.offset = offset 1420 | 1421 | return nil 1422 | } 1423 | 1424 | func (instruction *MoveWithZeroInstruction) execute() { 1425 | value := int64(instruction.constant) 1426 | offset := uint(16 * instruction.offset) 1427 | value = value << offset 1428 | setRegisterValue(instruction.reg1, value) 1429 | InstructionMem.updatePC() 1430 | } 1431 | 1432 | /* 1433 | INSTRUCTION : MOVE WITH KEEP 1434 | 1435 | Example : MOVK X1, 20, LSL 0 1436 | Meaning : X1 = 20 or 20*(2^16) or 20*(2^32) or 20*(2^48) 1437 | 1438 | Comments : Loads 16-bit constant, rest unchanged 1439 | */ 1440 | type MoveWithKeepInstruction struct { 1441 | inst string 1442 | reg1 uint 1443 | constant uint16 1444 | offset uint 1445 | } 1446 | 1447 | func (instruction *MoveWithKeepInstruction) checkSyntax() error { 1448 | r, _ := regexp.Compile("^MOVK X([0-9]|1[0-9]|2[0-7]), (0|[1-9][0-9]*), LSL (0|1|2|3)$") 1449 | if r.MatchString(instruction.inst) == false { 1450 | return errors.New("Syntax error occurred in " + instruction.inst) 1451 | } 1452 | return nil 1453 | } 1454 | 1455 | func (instruction *MoveWithKeepInstruction) parse() error { 1456 | statement := instruction.inst 1457 | var indexX, indexComma int 1458 | 1459 | indexX = strings.Index(statement, "X") 1460 | indexComma = strings.Index(statement, ",") 1461 | register, _ := strconv.Atoi(statement[indexX+1 : indexComma]) 1462 | 1463 | statement = strings.TrimSpace(statement[indexComma+1:]) 1464 | indexComma = strings.Index(statement, ",") 1465 | constant, _ := strconv.Atoi(statement[:indexComma]) 1466 | 1467 | offset := uint(statement[len(statement)-1] - '0') 1468 | 1469 | instruction.reg1 = uint(register) 1470 | instruction.constant = uint16(constant) 1471 | instruction.offset = offset 1472 | 1473 | return nil 1474 | } 1475 | 1476 | func (instruction *MoveWithKeepInstruction) execute() { 1477 | value := int64(instruction.constant) 1478 | offset := uint(16 * instruction.offset) 1479 | value = value << offset 1480 | registerValue := getRegisterValue(instruction.reg1) 1481 | 1482 | var lastBitIndex uint 1483 | lastBitIndex = offset + 15 1484 | 1485 | for i := offset; i <= lastBitIndex; i++ { 1486 | if value&(1<> 10 1879 | 1880 | Comments : Right shifts X2 by a constant, stores result in X1 1881 | */ 1882 | type RightShiftInstruction struct { 1883 | inst string 1884 | reg1 uint 1885 | reg2 uint 1886 | offset uint 1887 | } 1888 | 1889 | func (instruction *RightShiftInstruction) checkSyntax() error { 1890 | r, _ := regexp.Compile("^LSR X([0-9]|1[0-9]|2[0-7]), X(ZR|[0-9]|1[0-9]|2[0-7]), (0|[1-9][0-9]*)$") 1891 | if r.MatchString(instruction.inst) == false { 1892 | return errors.New("Syntax error occurred in " + instruction.inst) 1893 | } 1894 | return nil 1895 | } 1896 | 1897 | func (instruction *RightShiftInstruction) parse() error { 1898 | statement := instruction.inst 1899 | var registers [2]int 1900 | var i, indexX, indexComma, indexHash int 1901 | for i = 0; i < 2; i++ { 1902 | indexX = strings.Index(statement, "X") 1903 | indexComma = strings.Index(statement, ",") 1904 | if statement[indexX+1:indexComma] == "ZR" { 1905 | registers[i] = 31 1906 | } else { 1907 | registers[i], _ = strconv.Atoi(statement[indexX+1 : indexComma]) 1908 | } 1909 | statement = statement[indexComma+1:] 1910 | } 1911 | indexHash = strings.Index(statement, "#") 1912 | offset, _ := strconv.Atoi(statement[indexHash+1:]) 1913 | 1914 | instruction.reg1 = uint(registers[0]) 1915 | instruction.reg2 = uint(registers[1]) 1916 | instruction.offset = uint(offset) 1917 | 1918 | return nil 1919 | } 1920 | 1921 | func (instruction *RightShiftInstruction) execute() { 1922 | result := getRegisterValue(instruction.reg2) >> instruction.offset 1923 | setRegisterValue(instruction.reg1, result) 1924 | InstructionMem.updatePC() 1925 | } 1926 | 1927 | /* 1928 | INSTRUCTION : COMPARE AND BRANCH ON EQUAL 0 1929 | 1930 | Example : CBZ X1, label 1931 | Meaning : if (X1 == 0) go to label 1932 | 1933 | Comments : Equal 0 test; PC-relative branch 1934 | */ 1935 | type BranchOnZeroInstruction struct { 1936 | inst string 1937 | reg1 uint 1938 | offset int64 1939 | } 1940 | 1941 | func (instruction *BranchOnZeroInstruction) checkSyntax() error { 1942 | r, _ := regexp.Compile("^CBZ X([0-9]|1[0-9]|2[0-7]), ([a-zA-Z][[:alnum:]]*)$") 1943 | if r.MatchString(instruction.inst) == false { 1944 | return errors.New("Syntax error occurred in " + instruction.inst) 1945 | } 1946 | return nil 1947 | } 1948 | 1949 | func (instruction *BranchOnZeroInstruction) parse() error { 1950 | statement := instruction.inst 1951 | var indexX, indexComma int 1952 | 1953 | indexX = strings.Index(statement, "X") 1954 | indexComma = strings.Index(statement, ",") 1955 | 1956 | register, _ := strconv.Atoi(statement[indexX+1 : indexComma]) 1957 | labelName := strings.TrimSpace(statement[indexComma+1:]) 1958 | labelPC, isValidLabel := InstructionMem.Labels[labelName] 1959 | 1960 | if !isValidLabel { 1961 | return errors.New("Invalid label name " + labelName + " in " + instruction.inst) 1962 | } 1963 | 1964 | instruction.reg1 = uint(register) 1965 | instruction.offset = labelPC - InstructionMem.PC 1966 | 1967 | return nil 1968 | } 1969 | 1970 | func (instruction *BranchOnZeroInstruction) execute() { 1971 | if getRegisterValue(instruction.reg1) == 0 { 1972 | InstructionMem.updatePC(instruction.offset) 1973 | } else { 1974 | InstructionMem.updatePC() 1975 | } 1976 | } 1977 | 1978 | /* 1979 | INSTRUCTION : COMPARE AND BRANCH ON NOT EQUAL 0 1980 | 1981 | Example : CBNZ X1, label 1982 | Meaning : if (X1 != 0) go to label 1983 | 1984 | Comments : NotEqual 0 test; PC-relative branch 1985 | */ 1986 | type BranchOnNonZeroInstruction struct { 1987 | inst string 1988 | reg1 uint 1989 | offset int64 1990 | } 1991 | 1992 | func (instruction *BranchOnNonZeroInstruction) checkSyntax() error { 1993 | r, _ := regexp.Compile("^CBNZ X([0-9]|1[0-9]|2[0-7]), ([a-zA-Z][[:alnum:]]*)$") 1994 | if r.MatchString(instruction.inst) == false { 1995 | return errors.New("Syntax error occurred in " + instruction.inst) 1996 | } 1997 | return nil 1998 | } 1999 | 2000 | func (instruction *BranchOnNonZeroInstruction) parse() error { 2001 | statement := instruction.inst 2002 | var indexX, indexComma int 2003 | 2004 | indexX = strings.Index(statement, "X") 2005 | indexComma = strings.Index(statement, ",") 2006 | 2007 | register, _ := strconv.Atoi(statement[indexX+1 : indexComma]) 2008 | labelName := strings.TrimSpace(statement[indexComma+1:]) 2009 | labelPC, isValidLabel := InstructionMem.Labels[labelName] 2010 | 2011 | if !isValidLabel { 2012 | return errors.New("Invalid label name " + labelName + " in " + instruction.inst) 2013 | } 2014 | 2015 | instruction.reg1 = uint(register) 2016 | instruction.offset = labelPC - InstructionMem.PC 2017 | 2018 | return nil 2019 | } 2020 | 2021 | func (instruction *BranchOnNonZeroInstruction) execute() { 2022 | if getRegisterValue(instruction.reg1) != 0 { 2023 | InstructionMem.updatePC(instruction.offset) 2024 | } else { 2025 | InstructionMem.updatePC() 2026 | } 2027 | } 2028 | 2029 | /* 2030 | INSTRUCTION : CONDITIONAL BRANCH 2031 | 2032 | Example : B.cond label 2033 | Meaning : if (condition true) go to label 2034 | 2035 | Comments : Test condition codes; if true, then branch 2036 | */ 2037 | type ConditionalBranchInstruction struct { 2038 | inst string 2039 | offset int64 2040 | condition string 2041 | } 2042 | 2043 | func (instruction *ConditionalBranchInstruction) checkSyntax() error { 2044 | r, _ := regexp.Compile("^B\\.(EQ|NE|LT|LE|GT|GE|LO|LS|HI|HS) ([a-zA-Z][[:alnum:]]*)$") 2045 | if r.MatchString(instruction.inst) == false { 2046 | return errors.New("Syntax error occurred in " + instruction.inst) 2047 | } 2048 | return nil 2049 | } 2050 | 2051 | func (instruction *ConditionalBranchInstruction) parse() error { 2052 | statement := instruction.inst 2053 | 2054 | conditionCode := statement[2:4] 2055 | labelName := strings.TrimSpace(statement[5:]) 2056 | labelPC, isValidLabel := InstructionMem.Labels[labelName] 2057 | 2058 | if !isValidLabel { 2059 | return errors.New("Invalid label name " + labelName + " in " + instruction.inst) 2060 | } 2061 | 2062 | instruction.condition = conditionCode 2063 | instruction.offset = labelPC - InstructionMem.PC 2064 | 2065 | return nil 2066 | } 2067 | 2068 | func (instruction *ConditionalBranchInstruction) execute() { 2069 | is_branching := false 2070 | 2071 | switch instruction.condition { 2072 | 2073 | case "EQ": 2074 | is_branching = flagZero 2075 | break 2076 | case "NE": 2077 | is_branching = !flagZero 2078 | break 2079 | case "LT": 2080 | is_branching = (flagNegative != flagOverflow) 2081 | break 2082 | case "LE": 2083 | is_branching = !(flagZero == false && flagNegative == flagOverflow) 2084 | break 2085 | case "GT": 2086 | is_branching = (flagZero == false && flagNegative == flagOverflow) 2087 | break 2088 | case "GE": 2089 | is_branching = (flagNegative == flagOverflow) 2090 | break 2091 | case "LO": 2092 | is_branching = !flagCarry 2093 | break 2094 | case "LS": 2095 | is_branching = !(flagZero == false && flagCarry == true) 2096 | break 2097 | case "HI": 2098 | is_branching = (flagZero == false && flagCarry == true) 2099 | break 2100 | case "HS": 2101 | is_branching = flagCarry 2102 | break 2103 | 2104 | } 2105 | 2106 | if is_branching { 2107 | InstructionMem.updatePC(instruction.offset) 2108 | } else { 2109 | InstructionMem.updatePC() 2110 | } 2111 | } 2112 | 2113 | /* 2114 | INSTRUCTION : UNCONDITIONAL BRANCH 2115 | 2116 | Example : B label 2117 | Meaning : go to label 2118 | 2119 | Comments : Branch to PC-relative target address 2120 | */ 2121 | type BranchInstruction struct { 2122 | inst string 2123 | offset int64 2124 | } 2125 | 2126 | func (instruction *BranchInstruction) checkSyntax() error { 2127 | r, _ := regexp.Compile("^B ([a-zA-Z][[:alnum:]]*)$") 2128 | if r.MatchString(instruction.inst) == false { 2129 | return errors.New("Syntax error occurred in " + instruction.inst) 2130 | } 2131 | return nil 2132 | } 2133 | 2134 | func (instruction *BranchInstruction) parse() error { 2135 | statement := instruction.inst 2136 | 2137 | labelName := strings.TrimSpace(statement[2:]) 2138 | labelPC, isValidLabel := InstructionMem.Labels[labelName] 2139 | 2140 | if !isValidLabel { 2141 | return errors.New("Invalid label name " + labelName + " in " + instruction.inst) 2142 | } 2143 | 2144 | instruction.offset = labelPC - InstructionMem.PC 2145 | 2146 | return nil 2147 | } 2148 | 2149 | func (instruction *BranchInstruction) execute() { 2150 | InstructionMem.updatePC(instruction.offset) 2151 | } 2152 | 2153 | /* 2154 | INSTRUCTION : UNCONDITIONAL BRANCH TO REGISTER 2155 | 2156 | Example : BR LR 2157 | Meaning : go to address stored in LR 2158 | 2159 | Comments : Branch to address stored in register. Used for switch, procedure return 2160 | */ 2161 | type BranchToRegisterInstruction struct { 2162 | inst string 2163 | reg1 uint 2164 | offset int64 2165 | } 2166 | 2167 | func (instruction *BranchToRegisterInstruction) checkSyntax() error { 2168 | r, _ := regexp.Compile("^BR (X([0-9]|1[0-9]|2[0-7])|LR)$") 2169 | if r.MatchString(instruction.inst) == false { 2170 | return errors.New("Syntax error occurred in " + instruction.inst) 2171 | } 2172 | return nil 2173 | } 2174 | 2175 | func (instruction *BranchToRegisterInstruction) parse() error { 2176 | statement := instruction.inst 2177 | registerName := strings.TrimSpace(statement[3:]) 2178 | var register uint 2179 | 2180 | if strings.Compare(registerName, "LR") == 0 { 2181 | register = 30 2182 | } else { 2183 | registerValue, _ := strconv.Atoi(statement[4:]) 2184 | register = uint(registerValue) 2185 | } 2186 | 2187 | if !IsValidPC(getRegisterValue(register)) { 2188 | return errors.New("Invalid address in register " + registerName + " in " + instruction.inst) 2189 | } 2190 | 2191 | instruction.reg1 = register 2192 | instruction.offset = getRegisterValue(register) - InstructionMem.PC 2193 | 2194 | return nil 2195 | } 2196 | 2197 | func (instruction *BranchToRegisterInstruction) execute() { 2198 | InstructionMem.updatePC(instruction.offset) 2199 | } 2200 | 2201 | /* 2202 | INSTRUCTION : UNCONDITIONAL BRANCH WITH LINK 2203 | 2204 | Example : BL label 2205 | Meaning : X30 = PC + 4; go to label 2206 | 2207 | Comments : For procedure call (PC-relative) 2208 | */ 2209 | type BranchWithLinkInstruction struct { 2210 | inst string 2211 | offset int64 2212 | } 2213 | 2214 | func (instruction *BranchWithLinkInstruction) checkSyntax() error { 2215 | r, _ := regexp.Compile("^BL ([a-zA-Z][[:alnum:]]*)$") 2216 | if r.MatchString(instruction.inst) == false { 2217 | return errors.New("Syntax error occurred in " + instruction.inst) 2218 | } 2219 | return nil 2220 | } 2221 | 2222 | func (instruction *BranchWithLinkInstruction) parse() error { 2223 | statement := instruction.inst 2224 | 2225 | labelName := strings.TrimSpace(statement[3:]) 2226 | labelPC, isValidLabel := InstructionMem.Labels[labelName] 2227 | 2228 | if !isValidLabel { 2229 | return errors.New("Invalid label name " + labelName + " in " + instruction.inst) 2230 | } 2231 | 2232 | instruction.offset = labelPC - InstructionMem.PC 2233 | 2234 | return nil 2235 | } 2236 | 2237 | func (instruction *BranchWithLinkInstruction) execute() { 2238 | setRegisterValue(30, InstructionMem.PC+INCREMENT) 2239 | InstructionMem.updatePC(instruction.offset) 2240 | } 2241 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ARMed 2 | --- 3 | #### A basic ARM emulator written in Golang 4 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/coderick14/ARMed/issues) 5 | [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.png?v=103)](https://github.com/coderick14/ARMed) 6 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 7 | [![GoDoc](https://godoc.org/github.com/coderick14/ARMed?status.svg)](https://godoc.org/github.com/coderick14/ARMed) 8 | 9 | ![ARMed logo](https://github.com/coderick14/ARMed/blob/dev/images/logo.png "ARMed - an ARM emulator written in Golang" ) 10 | 11 | #### Build instructions 12 | ##### Build from source 13 | Requires Go to be [installed](https://golang.org/doc/install) and [configured](https://golang.org/doc/install#testing) 14 | ``` 15 | go get github.com/coderick14/ARMed 16 | ``` 17 | 18 | ##### Download the compiled binary 19 | Just download the binary for your required OS and architecture from [releases](https://github.com/coderick14/ARMed/releases) 20 | 21 | #### Usage 22 | `ARMed --help` will show all the usage details 23 | ``` 24 | ARMed version 1.0 25 | Author : https://github.com/coderick14 26 | 27 | ARMed is a very basic emulator of the ARM instruction set written in Golang 28 | USAGE : ARMed [OPTIONS]... SOURCE_FILE 29 | 30 | --all show all register values after an instruction, with updated ones in color 31 | --end show updated registers only once, at the end of the program. Overrides --all 32 | --no-log suppress logs of statements being executed 33 | --help display help 34 | 35 | Found a bug? Feel free to raise an issue on https://github.com/coderick14/ARMed 36 | Contributions welcome :) 37 | ``` 38 | 39 | --- 40 | 41 | ##### Contributions 42 | Found a bug? Or maybe add support for some more instructions? Feel free to open up a pull request or raise an issue!! 43 | 44 | --- 45 | 46 | ![ARMed demo GIF](https://github.com/coderick14/ARMed/blob/dev/images/demo.gif "Simple demo of how ARMed works" ) 47 | ##### NOTE : On Windows, if your cmd does not support unicode characters, pipe your output to a file. 48 | ``` 49 | ARMed.exe myfile > output.txt 50 | ``` 51 | Then view the file in your favourite editor (Notepad++, Wordpad, Sublime Text etc) 52 | 53 | #### Instructions supported in v1.0 54 | 55 | ``` 56 | INSTRUCTION : ADDITION 57 | Example : ADD X1, X2, X3 58 | Meaning : X1 = X2 + X3 59 | ``` 60 | 61 | ``` 62 | INSTRUCTION : SUBTRACTION 63 | Example : SUB X1, X2, X3 64 | Meaning : X1 = X2 - X3 65 | ``` 66 | 67 | ``` 68 | INSTRUCTION : MULTIPLICATION 69 | Example : MUL X1, X2, X3 70 | Meaning : X1 = X2 * X3 71 | ``` 72 | 73 | ``` 74 | INSTRUCTION : ADD IMMEDIATE 75 | Example : ADDI X1, X2, #40 76 | Meaning : X1 = X2 + 40 77 | ``` 78 | 79 | ``` 80 | INSTRUCTION : SUB IMMEDIATE 81 | Example : SUBI X1, X2, #40 82 | Meaning : X1 = X2 - 40 83 | ``` 84 | 85 | ``` 86 | INSTRUCTION : ADD AND SET FLAGS 87 | Example : ADDS X1, X2, X3 88 | Meaning : X1 = X2 + X3 89 | Comments : Adds and sets condition codes 90 | ``` 91 | 92 | ``` 93 | INSTRUCTION : SUB AND SET FLAGS 94 | Example : SUBS X1, X2, X3 95 | Meaning : X1 = X2 - X3 96 | Comments : Subtracts and sets condition codes 97 | ``` 98 | 99 | ``` 100 | INSTRUCTION : ADD IMMEDIATE AND SET FLAGS 101 | Example : ADDIS X1, X2, #40 102 | Meaning : X1 = X2 + 40 103 | Comments : Adds constant and sets condition codes 104 | ``` 105 | 106 | ``` 107 | INSTRUCTION : SUB IMMEDIATE AND SET FLAGS 108 | Example : SUBIS X1, X2, #40 109 | Meaning : X1 = X2 - 40 110 | Comments : Subtracts constant and sets condition codes 111 | ``` 112 | 113 | ``` 114 | INSTRUCTION : LOAD 115 | Example : LDUR X1, [X2, #40] 116 | Meaning : X1 = Memory[X2 + 40] 117 | Comments : Word from memory to register 118 | ``` 119 | 120 | ``` 121 | INSTRUCTION : STORE 122 | Example : STUR X1, [X2, #40] 123 | Meaning : Memory[X2 + 40] = X1 124 | Comments : Word from register to memory 125 | ``` 126 | 127 | ``` 128 | INSTRUCTION : LOAD HALFWORD 129 | Example : LDURH X1, [X2, #40] 130 | Meaning : X1 = Memory[X2 + 40] 131 | Comments : Halfword from memory to register 132 | ``` 133 | 134 | ``` 135 | INSTRUCTION : STORE HALFWORD 136 | Example : STURH X1, [X2, #40] 137 | Meaning : Memory[X2 + 40] = X1 138 | Comments : Halfword from register to memory 139 | ``` 140 | 141 | ``` 142 | INSTRUCTION : LOAD BYTE 143 | Example : LDURB X1, [X2, #40] 144 | Meaning : X1 = Memory[X2 + 40] 145 | Comments : Byte from memory to register 146 | ``` 147 | 148 | ``` 149 | INSTRUCTION : STORE BYTE 150 | Example : STURB X1, [X2, #40] 151 | Meaning : Memory[X2 + 40] = X1 152 | Comments : Byte from register to memory 153 | ``` 154 | 155 | ``` 156 | INSTRUCTION : MOVE WITH ZERO 157 | Example : MOVZ X1, 20, LSL 0 158 | Meaning : X1 = 20 or 20*(2^16) or 20*(2^32) or 20*(2^48) 159 | Comments : Loads 16-bit constant, rest zeroes 160 | ``` 161 | 162 | ``` 163 | INSTRUCTION : MOVE WITH KEEP 164 | Example : MOVK X1, 20, LSL 0 165 | Meaning : X1 = 20 or 20*(2^16) or 20*(2^32) or 20*(2^48) 166 | Comments : Loads 16-bit constant, rest unchanged 167 | ``` 168 | 169 | ``` 170 | INSTRUCTION : LOGICAL AND 171 | Example : AND X1, X2, X3 172 | Meaning : X1 = X2 & X3 173 | Comments : Bitwise-And of X2 and X3, stores result in X1 174 | ``` 175 | 176 | ``` 177 | INSTRUCTION : LOGICAL OR 178 | Example : ORR X1, X2, X3 179 | Meaning : X1 = X2 | X3 180 | Comments : Bitwise-Or of X2 and X3, stores result in X1 181 | ``` 182 | 183 | ``` 184 | INSTRUCTION : LOGICAL EXCLUSIVE-OR 185 | Example : EOR X1, X2, X3 186 | Meaning : X1 = X2 ^ X3 187 | Comments : Bitwise-Xor of X2 and X3, stores result in X1 188 | ``` 189 | 190 | ``` 191 | INSTRUCTION : LOGICAL AND IMMEDIATE 192 | Example : ANDI X1, X2, #20 193 | Meaning : X1 = X2 & 20 194 | Comments : Bitwise-And of X2 with a constant, stores result in X1 195 | ``` 196 | 197 | ``` 198 | INSTRUCTION : LOGICAL OR IMMEDIATE 199 | Example : ORRI X1, X2, #20 200 | Meaning : X1 = X2 | 20 201 | Comments : Bitwise-Or of X2 with a constant, stores result in X1 202 | ``` 203 | 204 | ``` 205 | INSTRUCTION : LOGICAL EXCLUSIVE-OR IMMEDIATE 206 | Example : EORI X1, X2, #20 207 | Meaning : X1 = X2 ^ 20 208 | Comments : Bitwise-Xor of X2 with a constant, stores result in X1 209 | ``` 210 | 211 | ``` 212 | INSTRUCTION : LOGICAL LEFT SHIFT 213 | Example : LSL X1, X2, #10 214 | Meaning : X1 = X2 << 10 215 | Comments : Left shifts X2 by a constant, stores result in X1 216 | ``` 217 | 218 | ``` 219 | INSTRUCTION : LOGICAL RIGHT SHIFT 220 | Example : LSR X1, X2, #10 221 | Meaning : X1 = X2 >> 10 222 | Comments : Right shifts X2 by a constant, stores result in X1 223 | ``` 224 | 225 | ``` 226 | INSTRUCTION : COMPARE AND BRANCH ON EQUAL 0 227 | Example : CBZ X1, label 228 | Meaning : if (X1 == 0) go to label 229 | Comments : Equal 0 test; PC-relative branch 230 | ``` 231 | 232 | ``` 233 | INSTRUCTION : COMPARE AND BRANCH ON NOT EQUAL 0 234 | Example : CBNZ X1, label 235 | Meaning : if (X1 != 0) go to label 236 | Comments : NotEqual 0 test; PC-relative branch 237 | ``` 238 | 239 | ``` 240 | INSTRUCTION : CONDITIONAL BRANCH 241 | Example : B.cond label 242 | Meaning : if (condition true) go to label 243 | Comments : Test condition codes; if true, then branch 244 | ``` 245 | 246 | ``` 247 | INSTRUCTION : UNCONDITIONAL BRANCH 248 | Example : B label 249 | Meaning : go to label 250 | Comments : Branch to PC-relative target address 251 | ``` 252 | 253 | ``` 254 | INSTRUCTION : UNCONDITIONAL BRANCH TO REGISTER 255 | Example : BR LR 256 | Meaning : go to address stored in LR 257 | Comments : Branch to address stored in register. Used for switch, procedure return 258 | ``` 259 | 260 | ``` 261 | INSTRUCTION : UNCONDITIONAL BRANCH WITH LINK 262 | Example : BL label 263 | Meaning : X30 = PC + 4; go to label 264 | Comments : For procedure call (PC-relative) 265 | ``` 266 | -------------------------------------------------------------------------------- /arm.go: -------------------------------------------------------------------------------- 1 | /* 2 | ARMed version 1.0 3 | 4 | Author : https://github.com/coderick14 5 | 6 | ARMed is a very basic emulator of the ARM instruction set written in Golang 7 | USAGE : ARMed [OPTIONS]... SOURCE_FILE 8 | 9 | Example SOURCE_FILE : 10 | 11 | ADDI X0, XZR, #3; 12 | BL fact; 13 | B Exit; 14 | fact: SUBI SP, SP, #8; 15 | STUR LR, [SP, #4]; 16 | STUR X0, [SP, #0]; 17 | SUBIS X9, X0, #1; 18 | B.GE L1; 19 | ADDI X1, XZR, #1; 20 | ADDI SP, SP, #8; 21 | BR LR; 22 | L1: SUBI X0, X0, #1; 23 | BL fact; 24 | LDUR X0, [SP, #0]; 25 | LDUR LR, [SP, #4]; 26 | ADDI SP, SP, #8; 27 | MUL X1, X0, X1; 28 | BR LR; 29 | Exit:; 30 | 31 | 32 | --all show all register values after an instruction, with updated ones in color 33 | --end show updated registers only once, at the end of the program. Overrides --all 34 | --no-log suppress logs of statements being executed 35 | --help display help 36 | 37 | Found a bug? Feel free to raise an issue on https://github.com/coderick14/ARMed 38 | 39 | Contributions welcome :) 40 | */ 41 | package main 42 | 43 | import ( 44 | "bufio" 45 | "errors" 46 | "flag" 47 | "fmt" 48 | Memory "github.com/coderick14/ARMed/Memory" 49 | "io" 50 | "os" 51 | "strings" 52 | ) 53 | 54 | const helpString = `ARMed version 1.0 55 | Author : https://github.com/coderick14 56 | 57 | ARMed is a very basic emulator of the ARM instruction set written in Golang 58 | USAGE : ARMed [OPTIONS]... SOURCE_FILE 59 | 60 | --all show all register values after an instruction, with updated ones in color 61 | --end show updated registers only once, at the end of the program. Overrides --all 62 | --no-log suppress logs of statements being executed 63 | --help display help 64 | 65 | Found a bug? Feel free to raise an issue on https://github.com/coderick14/ARMed 66 | Contributions welcome :)` 67 | 68 | func main() { 69 | var ( 70 | err error 71 | choice string 72 | ) 73 | helpPtr := flag.Bool("help", false, "Display help") 74 | allPtr := flag.Bool("all", false, "Display all registers after each instruction") 75 | endPtr := flag.Bool("end", false, "Display registers only at end") 76 | logPtr := flag.Bool("no-log", false, "Suppress log messages") 77 | 78 | flag.Parse() 79 | 80 | if *helpPtr == true { 81 | fmt.Println(helpString) 82 | return 83 | } 84 | 85 | if len(flag.Args()) == 0 { 86 | err = errors.New("Error : Missing filename.\n Type ARMed --help for further help") 87 | fmt.Println(err) 88 | return 89 | } 90 | 91 | fileName := flag.Args()[0] 92 | 93 | file, err := os.Open(fileName) 94 | if err != nil { 95 | fmt.Println("Error opening file : ", err) 96 | return 97 | } 98 | defer file.Close() 99 | 100 | reader := bufio.NewReader(file) 101 | 102 | for { 103 | line, err := reader.ReadString(';') 104 | if err == io.EOF { 105 | if len(line) > 1 { 106 | fmt.Println("Missing semicolon near :", line) 107 | return 108 | } 109 | break 110 | } else if err != nil { 111 | fmt.Println("Error while reading file : ", err) 112 | return 113 | } 114 | line = strings.TrimSpace(strings.TrimRight(line, ";")) 115 | if len(line) != 0 { 116 | Memory.InstructionMem.Instructions = append(Memory.InstructionMem.Instructions, line) 117 | } 118 | } 119 | 120 | Memory.InitRegisters() 121 | Memory.InstructionMem.ExtractLabels() 122 | 123 | if *endPtr == true { 124 | Memory.SaveRegisters() 125 | for Memory.IsValidPC(Memory.InstructionMem.PC) { 126 | if *logPtr == false { 127 | fmt.Println("Executing :", Memory.InstructionMem.Instructions[Memory.InstructionMem.PC]) 128 | } 129 | err = Memory.InstructionMem.ValidateAndExecuteInstruction() 130 | if err != nil { 131 | fmt.Println(err) 132 | return 133 | } 134 | } 135 | Memory.ShowRegisters(false) 136 | 137 | } else { 138 | 139 | for Memory.IsValidPC(Memory.InstructionMem.PC) { 140 | Memory.SaveRegisters() 141 | if *logPtr == false { 142 | fmt.Println("Executing :", Memory.InstructionMem.Instructions[Memory.InstructionMem.PC]) 143 | } 144 | err = Memory.InstructionMem.ValidateAndExecuteInstruction() 145 | if err != nil { 146 | fmt.Println(err) 147 | return 148 | } 149 | Memory.ShowRegisters(*allPtr) 150 | fmt.Printf("Continue [Y/n]? : ") 151 | fmt.Scanln(&choice) 152 | if choice == "n" { 153 | break; 154 | } 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /gen_bin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Generating binary for linuxAMD64..." 4 | env GOOS=linux GOARCH=amd64 go build 5 | zip linuxAMD64.zip ARMed 6 | echo "Done." 7 | 8 | echo "Generating binary for linuxARM64..." 9 | env GOOS=linux GOARCH=arm64 go build 10 | zip linuxARM64.zip ARMed 11 | echo "Done." 12 | 13 | echo "Generating binary for linuxARM32..." 14 | env GOOS=linux GOARCH=arm go build 15 | zip linuxARM32.zip ARMed 16 | echo "Done." 17 | 18 | echo "Generating binary for linux386..." 19 | env GOOS=linux GOARCH=386 go build 20 | zip linux386.zip ARMed 21 | echo "Done." 22 | 23 | echo "Generating binary for windows64..." 24 | env GOOS=windows GOARCH=amd64 go build 25 | zip windows64.zip ARMed.exe 26 | echo "Done." 27 | 28 | echo "Generating binary for windows32..." 29 | env GOOS=windows GOARCH=386 go build 30 | zip windows32.zip ARMed.exe 31 | echo "Done." 32 | 33 | # Generate system binary 34 | rm -f ARMed.exe ARMed 35 | go build 36 | 37 | mkdir -p binaries 38 | mv *.zip binaries -------------------------------------------------------------------------------- /images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderick14/ARMed/5f9b76bfc6771fd3ef6716618f2d3df8b23ad0f9/images/demo.gif -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coderick14/ARMed/5f9b76bfc6771fd3ef6716618f2d3df8b23ad0f9/images/logo.png --------------------------------------------------------------------------------