├── .gitignore ├── .idea ├── artifacts │ ├── mipsasm_linux_x86_64.xml │ ├── mipsasm_linux_x86_64_gtk3.xml │ ├── mipsasm_macosx_x86_64.xml │ ├── mipsasm_win32_x86.xml │ └── mipsasm_win32_x86_64.xml ├── compiler.xml ├── copyright │ ├── ZH_Copyright.xml │ └── profiles_settings.xml ├── description.html ├── dictionaries │ └── zh.xml ├── encodings.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── libraries │ ├── commons_cli_commons_cli_1_2.xml │ ├── org_apache_commons_commons_lang3_3_4.xml │ └── swt_4_4_2_gtk_linux_x86_64_debug.xml ├── misc.xml ├── modules.xml ├── project-template.xml ├── scopes │ └── scope_settings.xml ├── uiDesigner.xml └── vcs.xml ├── LICENSE.md ├── README.md ├── README_ZH_CN.md ├── art ├── app_icon.ico └── app_icon.zip ├── dist ├── .gitignore ├── launch4j-mipsasm-win32-x86.xml ├── launch4j-mipsasm-win32-x86_64.xml └── mipsasm-macosx-x86_64.sh ├── lib ├── swt-4.4.2-cocoa-macosx-x86_64.jar ├── swt-4.4.2-gtk-linux-x86_64-debug.jar ├── swt-4.4.2-gtk-linux-x86_64-src.zip ├── swt-4.4.2-gtk-linux-x86_64.jar ├── swt-4.4.2-win32-x86.jar └── swt-4.4.2-win32-x86_64.jar ├── mipsasm.iml ├── screenshot ├── app-gtk3.png └── app-windows.png ├── src ├── META-INF │ └── MANIFEST.MF ├── me │ └── zhanghai │ │ └── mipsasm │ │ ├── Build.java │ │ ├── Cli.java │ │ ├── Constants.java │ │ ├── InternalException.java │ │ ├── Main.java │ │ ├── assembler │ │ ├── Assemblable.java │ │ ├── Assembler.java │ │ ├── AssemblerException.java │ │ ├── AssemblerPreferences.java │ │ ├── AssemblyContext.java │ │ ├── AssemblyProvider.java │ │ ├── BackwardAddressException.java │ │ ├── CoprocessorFunction.java │ │ ├── DataDirective.java │ │ ├── Directive.java │ │ ├── DirectiveInformation.java │ │ ├── Immediate.java │ │ ├── Instruction.java │ │ ├── InstructionAssembler.java │ │ ├── InstructionAssemblers.java │ │ ├── InstructionIndex.java │ │ ├── InstructionInformation.java │ │ ├── Label.java │ │ ├── Offset.java │ │ ├── OffsetBase.java │ │ ├── OffsetLabel.java │ │ ├── OffsetTooLargeException.java │ │ ├── Operand.java │ │ ├── OperandInstance.java │ │ ├── OperandListPrototypes.java │ │ ├── OperandNotFoundException.java │ │ ├── OperandPrototype.java │ │ ├── OperandPrototypes.java │ │ ├── OperandType.java │ │ ├── Operation.java │ │ ├── Register.java │ │ ├── ShiftAmount.java │ │ ├── SpaceDirective.java │ │ ├── StorageDirective.java │ │ ├── Target.java │ │ ├── TargetLabel.java │ │ ├── TextDirective.java │ │ ├── UndefinedLabelException.java │ │ └── WordImmediate.java │ │ ├── disassembler │ │ ├── CoeReader.java │ │ ├── CoeReaderException.java │ │ ├── Disassembler.java │ │ ├── DisassemblerException.java │ │ ├── DisassemblyContext.java │ │ ├── InstructionDisassembler.java │ │ ├── InstructionDisassemblers.java │ │ ├── InstructionWordDisassembler.java │ │ ├── NoSuchOperationException.java │ │ ├── StorageDirectiveDisassembler.java │ │ └── WordDisassembler.java │ │ ├── gui │ │ ├── AboutDialog.java │ │ ├── FontDataBuilder.java │ │ ├── Ide.java │ │ ├── MenuItemBuilder.java │ │ ├── StyledTextMenuHelper.java │ │ ├── StyledTextStyleHelper.java │ │ ├── StyledTextUndoRedoHelper.java │ │ ├── SwtUtils.java │ │ └── Utf8Control.java │ │ ├── parser │ │ ├── AsciiDirectiveParser.java │ │ ├── AsciizDirectiveParser.java │ │ ├── ByteDirectiveParser.java │ │ ├── CoprocessorFunctionParser.java │ │ ├── DataDirectiveParser.java │ │ ├── DirectiveParser.java │ │ ├── EchoDirectiveParser.java │ │ ├── EvalDirectiveParser.java │ │ ├── HalfWordDirectiveParser.java │ │ ├── IllegalDirectiveException.java │ │ ├── IllegalInstructionException.java │ │ ├── IllegalLabelException.java │ │ ├── IllegalOperandException.java │ │ ├── IllegalStatementException.java │ │ ├── ImmediateParser.java │ │ ├── InstructionParser.java │ │ ├── JavaScriptParser.java │ │ ├── LabelAlreadyDefinedException.java │ │ ├── LabelOperandParser.java │ │ ├── LabelParser.java │ │ ├── LineParser.java │ │ ├── MigratorException.java │ │ ├── MultiplePendingLabelException.java │ │ ├── NoSuchDirectiveException.java │ │ ├── NoSuchOperationException.java │ │ ├── OffsetBaseParser.java │ │ ├── OffsetParser.java │ │ ├── OperandCountMismatchException.java │ │ ├── OperandListParser.java │ │ ├── Parser.java │ │ ├── ParserException.java │ │ ├── ParserSplitUtils.java │ │ ├── PendingLabelException.java │ │ ├── RegisterParser.java │ │ ├── ShiftAmountParser.java │ │ ├── SpaceDirectiveParser.java │ │ ├── SqsMigrator.java │ │ ├── StatementParser.java │ │ ├── StorageDirectiveParser.java │ │ ├── TargetLabelParser.java │ │ ├── TargetParser.java │ │ ├── TextDirectiveParser.java │ │ ├── Tokens.java │ │ ├── WordDirectiveParser.java │ │ └── WordImmediateParser.java │ │ ├── util │ │ ├── BitArray.java │ │ ├── HexUnescaper.java │ │ ├── IoUtils.java │ │ ├── RegexUtils.java │ │ ├── StringUtils.java │ │ └── UnsignedCompat.java │ │ └── writer │ │ ├── BinaryWriter.java │ │ ├── CoeWriter.java │ │ ├── DebugWriter.java │ │ ├── HexDebugWriter.java │ │ ├── Writer.java │ │ └── WriterException.java └── res │ ├── drawable │ ├── mipside_128.png │ ├── mipside_16.png │ ├── mipside_256.png │ ├── mipside_32.png │ ├── mipside_48.png │ ├── mipside_512.png │ └── mipside_64.png │ ├── font │ ├── SourceCodePro-Bold.ttf │ └── SourceCodePro-Regular.ttf │ └── string │ ├── mipside.properties │ └── mipside_zh_CN.properties └── test ├── .gitignore ├── computer_MCPU.s ├── hello_world.s ├── js.s ├── legacy └── computer_MCPU.asm ├── migrate.s └── test.s /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/workspace.xml 2 | out/ 3 | -------------------------------------------------------------------------------- /.idea/artifacts/mipsasm_linux_x86_64.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/mipsasm_linux_x86_64 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/artifacts/mipsasm_linux_x86_64_gtk3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/mipsasm_linux_x86_64_gtk3 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/artifacts/mipsasm_macosx_x86_64.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/mipsasm_macosx_x86_64 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/artifacts/mipsasm_win32_x86.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/mipsasm_win32_x86 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/artifacts/mipsasm_win32_x86_64.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/mipsasm_win32_x86_64 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | -------------------------------------------------------------------------------- /.idea/copyright/ZH_Copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/description.html: -------------------------------------------------------------------------------- 1 | Simple Java application that includes a class with main() method -------------------------------------------------------------------------------- /.idea/dictionaries/zh.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | assemblable 5 | disassemblers 6 | disassembly 7 | migrator 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 27 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/libraries/commons_cli_commons_cli_1_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/libraries/org_apache_commons_commons_lang3_3_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/libraries/swt_4_4_2_gtk_linux_x86_64_debug.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/project-template.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIPS Assembler and IDE 2 | 3 | [本文中文版](README_ZH_CN.md) 4 | 5 | This is my project for Computer Organization, Shi Qingsong, Zhejiang University. 6 | 7 | The MIPS assembler is based on the MIPS 32 specification, with some custom extensions. 8 | 9 | The MIPS IDE is built upon SWT, packaged with launch4j for Windows executable. 10 | 11 | ## Screenshot 12 | 13 | ![Windows](screenshot/app-windows.png) 14 | 15 | ![GTK3](screenshot/app-gtk3.png) 16 | 17 | ## Specification 18 | 19 | This MIPS assembler mainly complies with the specifications from "MIPS Assembly Language Programmer’s Guide" and "MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set". 20 | 21 | ## Instruction set 22 | 23 | 95 Instrucitons: 24 | 25 | - ADD 26 | - ADDI 27 | - ADDIU 28 | - ADDU 29 | - AND 30 | - ANDI 31 | - B 32 | - BEQ 33 | - BEQL 34 | - BGEZ 35 | - BGEZAL 36 | - BGEZALL 37 | - BGEZL 38 | - BGTZ 39 | - BGTZL 40 | - BLEZ 41 | - BLEZL 42 | - BLTZ 43 | - BLTZAL 44 | - BLTZALL 45 | - BLTZL 46 | - BNE 47 | - BNEL 48 | - BREAK 49 | - COP2 50 | - DERET 51 | - DIV 52 | - DIVU 53 | - ERET 54 | - J 55 | - JAL 56 | - JALR 57 | - JR 58 | - LA 59 | - LB 60 | - LBU 61 | - LDC1 62 | - LDC2 63 | - LH 64 | - LHU 65 | - LI 66 | - LL 67 | - LUI 68 | - LW 69 | - LWC1 70 | - LWC2 71 | - LWL 72 | - LWR 73 | - MFC0 74 | - MFHI 75 | - MFLO 76 | - MOVE 77 | - MOVN 78 | - MOVZ 79 | - MTC0 80 | - MTHI 81 | - MTLO 82 | - MULT 83 | - MULTU 84 | - NOR 85 | - NOP 86 | - OR 87 | - ORI 88 | - PREF 89 | - SB 90 | - SC 91 | - SDC1 92 | - SDC2 93 | - SH 94 | - SLL 95 | - SLLV 96 | - SLT 97 | - SLTI 98 | - SLTIU 99 | - SLTU 100 | - SRA 101 | - SRAV 102 | - SRL 103 | - SRLV 104 | - SUB 105 | - SUBU 106 | - SW 107 | - SWC1 108 | - SWC2 109 | - SWC3 110 | - SWL 111 | - SWR 112 | - TLBP 113 | - TLBR 114 | - TLBWI 115 | - TLBWR 116 | - SYSCALL 117 | - WAIT 118 | - XOR 119 | - XOR 120 | 121 | 10 directives: 122 | 123 | - .TEXT 124 | - .DATA 125 | - .ASCII 126 | - .ASCIIZ 127 | - .BYTE 128 | - .HALF 129 | - .WORD 130 | - .SPACE 131 | - .EVAL 132 | - .ECHO 133 | 134 | JavaScript expression is supported for operands, while `.eval` can evaluate a JavaScript expression anywhere and `.echo` can echo the JavaScript returned string as the source code to assemble in place. 135 | 136 | ## Assemble 137 | 138 | Numerous error checks are done during the process of assembly, including illegal operand, immediate overflow, missing or duplicate label, text and data section overlap, etc. 139 | 140 | Available output formats include binary, COE and a debug mode. 141 | 142 | ## Disassemble 143 | 144 | Disassembling can be done by opening a binary or COE file. All the instructions listed above and labels are supported, and multiple bytes of zero can be compressed into a `.space` directive. 145 | 146 | ## Graphical user interface 147 | 148 | - Native GUI on Linux, Windows and Mac OSX. 149 | 150 | - Drag-and-drop to open a file. 151 | 152 | - Printing support. 153 | 154 | - Line number and syntax highlighting. 155 | 156 | ## Command line interface 157 | 158 | ``` 159 | usage: mipsasm [OPTION]... 160 | -g,--graphical Launch graphical user interface 161 | -h,--help Display this help and exit 162 | -i,--input Read input from FILE 163 | -o,--output Write output to FILE 164 | -t,--terminal Launch in terminal mode 165 | -w,--writer Use writer of TYPE. TYPE can be 'binary', 'coe', 166 | 'debug' (the default), or 'hexdebug' 167 | ``` 168 | 169 | ## Sample code 170 | 171 | ```mipsasm 172 | # "Hello World" in MIPS assembly 173 | # From: http://labs.cs.upt.ro/labs/so2/html/resources/nachos-doc/mipsf.html 174 | 175 | # All program code is placed after the 176 | # .text assembler directive 177 | .text 0x0 178 | 179 | # The label 'main' represents the starting point 180 | main: 181 | # Run the print_string syscall which has code 4 182 | li $v0, 4 # Code for syscall: print_string 183 | la $a0, msg # Pointer to string (load the address of msg) 184 | syscall 185 | li $v0, 10 # Code for syscall: exit 186 | syscall 187 | 188 | # All memory structures are placed after the 189 | # .data assembler directive 190 | .data 0x20 191 | 192 | # The .asciiz assembler directive creates 193 | # an ASCII string in memory terminated by 194 | # the null character. Note that strings are 195 | # surrounded by double-quotes 196 | 197 | msg: .asciiz "Hello World!\n" 198 | ``` 199 | -------------------------------------------------------------------------------- /README_ZH_CN.md: -------------------------------------------------------------------------------- 1 | # MIPS 汇编器及集成开发环境 2 | 3 | 这是我为浙江大学计算机组成课程编写的项目。 4 | 5 | MIPS 汇编器主要遵循 MIPS 32 规格说明,并采用了一些自定义的扩展. 6 | 7 | MIPS 集成开发环境基于 SWT 构建,并使用 launch4j 打包为 Windows 可执行程序。 8 | 9 | ## 预览 10 | 11 | ![Windows](screenshot/app-windows.png) 12 | 13 | ![GTK3](screenshot/app-gtk3.png) 14 | 15 | ## 规范 16 | 17 | 本汇编器参考并主要遵循 MIPS Assembly Language Programmer’s Guide 及 MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set 所包含的规范。 18 | 19 | ## 指令集 20 | 21 | 支持以下 95 条指令: 22 | 23 | - ADD 24 | - ADDI 25 | - ADDIU 26 | - ADDU 27 | - AND 28 | - ANDI 29 | - B 30 | - BEQ 31 | - BEQL 32 | - BGEZ 33 | - BGEZAL 34 | - BGEZALL 35 | - BGEZL 36 | - BGTZ 37 | - BGTZL 38 | - BLEZ 39 | - BLEZL 40 | - BLTZ 41 | - BLTZAL 42 | - BLTZALL 43 | - BLTZL 44 | - BNE 45 | - BNEL 46 | - BREAK 47 | - COP2 48 | - DERET 49 | - DIV 50 | - DIVU 51 | - ERET 52 | - J 53 | - JAL 54 | - JALR 55 | - JR 56 | - LA 57 | - LB 58 | - LBU 59 | - LDC1 60 | - LDC2 61 | - LH 62 | - LHU 63 | - LI 64 | - LL 65 | - LUI 66 | - LW 67 | - LWC1 68 | - LWC2 69 | - LWL 70 | - LWR 71 | - MFC0 72 | - MFHI 73 | - MFLO 74 | - MOVE 75 | - MOVN 76 | - MOVZ 77 | - MTC0 78 | - MTHI 79 | - MTLO 80 | - MULT 81 | - MULTU 82 | - NOR 83 | - NOP 84 | - OR 85 | - ORI 86 | - PREF 87 | - SB 88 | - SC 89 | - SDC1 90 | - SDC2 91 | - SH 92 | - SLL 93 | - SLLV 94 | - SLT 95 | - SLTI 96 | - SLTIU 97 | - SLTU 98 | - SRA 99 | - SRAV 100 | - SRL 101 | - SRLV 102 | - SUB 103 | - SUBU 104 | - SW 105 | - SWC1 106 | - SWC2 107 | - SWC3 108 | - SWL 109 | - SWR 110 | - TLBP 111 | - TLBR 112 | - TLBWI 113 | - TLBWR 114 | - SYSCALL 115 | - WAIT 116 | - XOR 117 | - XOR 118 | 119 | 支持以下 10 条伪指令: 120 | 121 | - .TEXT 122 | - .DATA 123 | - .ASCII 124 | - .ASCIIZ 125 | - .BYTE 126 | - .HALF 127 | - .WORD 128 | - .SPACE 129 | - .EVAL 130 | - .ECHO 131 | 132 | 所有操作数均支持 JavaScript 表达式,同时`.EVAL`指令可以直接求值一个 JavaScript 表达式,`.ECHO`可以将 JavaScript 表达式的返回值作为一行 MIPS 代码就地进行汇编。 133 | 134 | ## 汇编功能 135 | 136 | 支持完备的错误检查,在参数不合法、立即数超出范围、标签缺失或重复、代码或数据段重叠等情况下输出错误信息。 137 | 138 | 支持的输出格式包括二进制、COE 和调试输出文件。 139 | 140 | 支持将旧格式导入至现有格式。 141 | 142 | ## 反汇编功能 143 | 144 | 支持以上所有指令所生成的二进制和 COE 文件。 145 | 146 | 支持标签的反汇编。 147 | 148 | 支持将二进制中大量 0 压缩为一条`.SPACE`伪指令。 149 | 150 | ## 命令行功能 151 | 152 | 支持以下命令格式: 153 | 154 | ``` 155 | usage: mipsasm [OPTION]... 156 | -g,--graphical Launch graphical user interface 157 | -h,--help Display this help and exit 158 | -i,--input Read input from FILE 159 | -o,--output Write output to FILE 160 | -t,--terminal Launch in terminal mode 161 | -w,--writer Use writer of TYPE. TYPE can be 'binary', 'coe', 162 | 'debug' (the default), or 'hexdebug' 163 | ``` 164 | 165 | ## 图形界面功能 166 | 167 | 支持在 Windows、Linux、Mac OSX 上使用原生控件显示图形界面。 168 | 169 | 支持文件、编辑、汇编菜单和相应快捷键。 170 | 171 | 支持拖拽打开文件。 172 | 173 | 支持打印。 174 | 175 | 支持语法高亮、行号显示。 176 | 177 | ## 示例代码 178 | 179 | MIPS 汇编代码: 180 | 181 | ```mipsasm 182 | # "Hello World" in MIPS assembly 183 | # From: http://labs.cs.upt.ro/labs/so2/html/resources/nachos-doc/mipsf.html 184 | 185 | # All program code is placed after the 186 | # .text assembler directive 187 | .text 0x0 188 | 189 | # The label 'main' represents the starting point 190 | main: 191 | # Run the print_string syscall which has code 4 192 | li $v0, 4 # Code for syscall: print_string 193 | la $a0, msg # Pointer to string (load the address of msg) 194 | syscall 195 | li $v0, 10 # Code for syscall: exit 196 | syscall 197 | 198 | # All memory structures are placed after the 199 | # .data assembler directive 200 | .data 0x20 201 | 202 | # The .asciiz assembler directive creates 203 | # an ASCII string in memory terminated by 204 | # the null character. Note that strings are 205 | # surrounded by double-quotes 206 | 207 | msg: .asciiz "Hello World!\n" 208 | ``` 209 | 210 | COE 输出: 211 | 212 | ```coe 213 | memory_initialization_radix=16; 214 | memory_initialization_vector= 215 | 3C020004, 34420000, 3C040020, 34840000, 0000000C, 3C02000A, 34420000, 0000000C, 216 | 48656C6C, 6F20576F, 726C6421, 0A000000; 217 | ``` 218 | -------------------------------------------------------------------------------- /art/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/art/app_icon.ico -------------------------------------------------------------------------------- /art/app_icon.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/art/app_icon.zip -------------------------------------------------------------------------------- /dist/.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | -------------------------------------------------------------------------------- /dist/launch4j-mipsasm-win32-x86.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | gui 5 | ../out/artifacts/mipsasm_win32_x86/mipsasm-win32-x86.jar 6 | out/mipsasm-win32-x86.exe 7 | 8 | 9 | . 10 | normal 11 | https://java.com/download/ 12 | 13 | false 14 | false 15 | 16 | ../art/app_icon.ico 17 | 18 | 19 | false 20 | false 21 | 1.7.0 22 | 23 | preferJre 24 | 32/64 25 | 26 | -------------------------------------------------------------------------------- /dist/launch4j-mipsasm-win32-x86_64.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | gui 5 | ../out/artifacts/mipsasm_win32_x86_64/mipsasm-win32-x86_64.jar 6 | out/mipsasm-win32-x86_64.exe 7 | 8 | 9 | . 10 | normal 11 | https://java.com/download/ 12 | 13 | false 14 | false 15 | 16 | ../art/app_icon.ico 17 | 18 | 19 | false 20 | false 21 | 1.7.0 22 | 23 | preferJre 24 | 64 25 | 26 | 27 | -------------------------------------------------------------------------------- /dist/mipsasm-macosx-x86_64.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec java \ 3 | -d64 \ 4 | -XstartOnFirstThread \ 5 | -jar mipsasm-macosx-x86_64.jar 6 | -------------------------------------------------------------------------------- /lib/swt-4.4.2-cocoa-macosx-x86_64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/lib/swt-4.4.2-cocoa-macosx-x86_64.jar -------------------------------------------------------------------------------- /lib/swt-4.4.2-gtk-linux-x86_64-debug.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/lib/swt-4.4.2-gtk-linux-x86_64-debug.jar -------------------------------------------------------------------------------- /lib/swt-4.4.2-gtk-linux-x86_64-src.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/lib/swt-4.4.2-gtk-linux-x86_64-src.zip -------------------------------------------------------------------------------- /lib/swt-4.4.2-gtk-linux-x86_64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/lib/swt-4.4.2-gtk-linux-x86_64.jar -------------------------------------------------------------------------------- /lib/swt-4.4.2-win32-x86.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/lib/swt-4.4.2-win32-x86.jar -------------------------------------------------------------------------------- /lib/swt-4.4.2-win32-x86_64.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/lib/swt-4.4.2-win32-x86_64.jar -------------------------------------------------------------------------------- /mipsasm.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /screenshot/app-gtk3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/screenshot/app-gtk3.png -------------------------------------------------------------------------------- /screenshot/app-windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/screenshot/app-windows.png -------------------------------------------------------------------------------- /src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: me.zhanghai.mipsasm.Main 3 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/Build.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm; 7 | 8 | public class Build { 9 | 10 | public static final String VERSION_NAME = "1.0.2"; 11 | 12 | private Build() {} 13 | } 14 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm; 7 | 8 | public class Constants { 9 | 10 | public static final int BYTE_LENGTH = 8; 11 | public static final int HALF_WORD_LENGTH = 16; 12 | public static final int WORD_LENGTH = 32; 13 | public static final int ADDRESS_LENGTH = WORD_LENGTH; 14 | public static final int INSTRUCTION_LENGTH = WORD_LENGTH; 15 | public static final int BYTES_PER_HALF_WORD = HALF_WORD_LENGTH / BYTE_LENGTH; 16 | public static final int BYTES_PER_WORD = WORD_LENGTH / BYTE_LENGTH; 17 | public static final int BYTES_PER_INSTRUCTION = INSTRUCTION_LENGTH / BYTE_LENGTH; 18 | } 19 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/InternalException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm; 7 | 8 | public class InternalException extends RuntimeException { 9 | 10 | public InternalException() {} 11 | 12 | public InternalException(String message) { 13 | super(message); 14 | } 15 | 16 | public InternalException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public InternalException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/Main.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm; 7 | 8 | import me.zhanghai.mipsasm.gui.Ide; 9 | import org.apache.commons.cli.CommandLine; 10 | import org.apache.commons.cli.ParseException; 11 | 12 | public class Main { 13 | 14 | public static void main(String[] args) { 15 | 16 | CommandLine commandLine; 17 | try { 18 | commandLine = Cli.parseCommandLine(args); 19 | } catch (ParseException e) { 20 | e.printStackTrace(); 21 | return; 22 | } 23 | if (!Cli.checkCommandLine(commandLine)) { 24 | return; 25 | } 26 | 27 | // If OPTION_TERMINAL is present, then there will be an option. 28 | if (Cli.hasGraphicalOption(commandLine) || !Cli.hasOption(commandLine)) { 29 | new Ide().run(); 30 | } else { 31 | Cli.run(commandLine); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Assemblable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public interface Assemblable { 9 | 10 | void allocate(AssemblyContext context); 11 | 12 | void write(AssemblyContext context) throws AssemblerException; 13 | } 14 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Assembler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class Assembler { 9 | 10 | private Assembler() {} 11 | 12 | public static void assemble(AssemblyContext context) throws AssemblerException { 13 | for (Assemblable assemblable : context.getAssemblableList()) { 14 | try { 15 | assemblable.write(context); 16 | } catch (AssemblerException e) { 17 | throw new AssemblerException("Assemblable: " + assemblable, e); 18 | } 19 | } 20 | context.packAssemblyToWords(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/AssemblerException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class AssemblerException extends Exception { 9 | 10 | public AssemblerException() {} 11 | 12 | public AssemblerException(String message) { 13 | super(message); 14 | } 15 | 16 | public AssemblerException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public AssemblerException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/AssemblerPreferences.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import java.util.prefs.Preferences; 9 | 10 | public class AssemblerPreferences { 11 | 12 | private enum Preference { 13 | 14 | DELAY_SLOT_ENABLED(true); 15 | 16 | private Object defaultValue; 17 | 18 | Preference(Object defaultValue) { 19 | this.defaultValue = defaultValue; 20 | } 21 | 22 | public T getDefaultValue() { 23 | //noinspection unchecked 24 | return (T) defaultValue; 25 | } 26 | } 27 | 28 | private static final Preferences PREFERENCES = Preferences.userNodeForPackage(AssemblerPreferences.class); 29 | 30 | private AssemblerPreferences() {} 31 | 32 | public static boolean getDelaySlotEnabled() { 33 | return PREFERENCES.getBoolean(Preference.DELAY_SLOT_ENABLED.name(), 34 | Preference.DELAY_SLOT_ENABLED.getDefaultValue()); 35 | } 36 | 37 | public static void setDelaySlotEnabled(boolean delaySlotEnabled) { 38 | PREFERENCES.putBoolean(Preference.DELAY_SLOT_ENABLED.name(), delaySlotEnabled); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/AssemblyProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.util.BitArray; 9 | 10 | public interface AssemblyProvider { 11 | 12 | BitArray assemble(AssemblyContext context) throws AssemblerException; 13 | } 14 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/BackwardAddressException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class BackwardAddressException extends IllegalArgumentException { 9 | 10 | public BackwardAddressException() {} 11 | 12 | public BackwardAddressException(String message) { 13 | super(message); 14 | } 15 | 16 | public BackwardAddressException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public BackwardAddressException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/CoprocessorFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.util.BitArray; 9 | 10 | public class CoprocessorFunction implements Operand, AssemblyProvider { 11 | 12 | private static final int LENGTH = 25; 13 | 14 | private BitArray value; 15 | 16 | private CoprocessorFunction(BitArray value) { 17 | this.value = value; 18 | } 19 | 20 | public static CoprocessorFunction of(BitArray value) { 21 | if (value.length() != LENGTH) { 22 | throw new IllegalArgumentException("Coprocessor function length != " + LENGTH + ": " + value.length()); 23 | } 24 | return new CoprocessorFunction(BitArray.copyOf(value)); 25 | } 26 | 27 | public static CoprocessorFunction of(int value) { 28 | return new CoprocessorFunction(BitArray.of(value, LENGTH)); 29 | } 30 | 31 | public BitArray getValue() { 32 | return value; 33 | } 34 | 35 | public BitArray assemble(AssemblyContext context) { 36 | return value; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return value.toString(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/DataDirective.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class DataDirective extends Directive { 9 | 10 | private WordImmediate address; 11 | 12 | private DataDirective(WordImmediate address) { 13 | this.address = address; 14 | } 15 | 16 | public static DataDirective of(WordImmediate address) { 17 | return new DataDirective(address); 18 | } 19 | 20 | public WordImmediate getAddress() { 21 | return address; 22 | } 23 | 24 | @Override 25 | public void allocate(AssemblyContext context) { 26 | context.allocateToAddress(address); 27 | } 28 | 29 | @Override 30 | public void write(AssemblyContext context) throws AssemblerException { 31 | context.writeToAddress(address); 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "." + DirectiveInformation.DATA.name().toLowerCase() + " " + address; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Directive.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public abstract class Directive implements Assemblable {} 9 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/DirectiveInformation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.parser.*; 9 | 10 | public enum DirectiveInformation { 11 | 12 | TEXT, 13 | DATA, 14 | ASCII, 15 | ASCIIZ, 16 | BYTE, 17 | HALF, 18 | WORD, 19 | SPACE, 20 | EVAL, 21 | ECHO; 22 | 23 | public void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 24 | switch (this) { 25 | case TEXT: 26 | TextDirectiveParser.parse(operandStringList, context); 27 | break; 28 | case DATA: 29 | DataDirectiveParser.parse(operandStringList, context); 30 | break; 31 | case ASCII: 32 | AsciiDirectiveParser.parse(operandStringList, context); 33 | break; 34 | case ASCIIZ: 35 | AsciizDirectiveParser.parse(operandStringList, context); 36 | break; 37 | case BYTE: 38 | ByteDirectiveParser.parse(operandStringList, context); 39 | break; 40 | case HALF: 41 | HalfWordDirectiveParser.parse(operandStringList, context); 42 | break; 43 | case WORD: 44 | WordDirectiveParser.parse(operandStringList, context); 45 | break; 46 | case SPACE: 47 | SpaceDirectiveParser.parse(operandStringList, context); 48 | break; 49 | case EVAL: 50 | EvalDirectiveParser.parse(operandStringList, context); 51 | break; 52 | case ECHO: 53 | EchoDirectiveParser.parse(operandStringList, context); 54 | break; 55 | default: 56 | throw new IllegalStateException("Parser not found: " + this); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Immediate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.util.BitArray; 10 | 11 | public class Immediate implements Operand, AssemblyProvider { 12 | 13 | static final int LENGTH = Constants.HALF_WORD_LENGTH; 14 | 15 | private BitArray value; 16 | 17 | private Immediate(BitArray value) { 18 | this.value = value; 19 | } 20 | 21 | public static Immediate of(int value) { 22 | return new Immediate(BitArray.ofInteger(value, LENGTH)); 23 | } 24 | 25 | public BitArray getValue() { 26 | return value; 27 | } 28 | 29 | @Override 30 | public BitArray assemble(AssemblyContext context) { 31 | return value; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return value.toDecimalString(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Instruction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.util.IoUtils; 9 | 10 | import java.util.Arrays; 11 | 12 | public class Instruction implements Assemblable { 13 | 14 | private Operation operation; 15 | private OperandInstance[] operandListInstance; 16 | 17 | private Instruction(Operation operation, OperandInstance[] operandListInstance) { 18 | this.operation = operation; 19 | this.operandListInstance = operandListInstance; 20 | } 21 | 22 | public static Instruction of(Operation operation, OperandInstance[] operandListInstance) { 23 | return new Instruction(operation, operandListInstance); 24 | } 25 | 26 | public Operation getOperation() { 27 | return operation; 28 | } 29 | 30 | public OperandInstance[] getOperandListInstance() { 31 | return operandListInstance; 32 | } 33 | 34 | public OperandInstance getOperandInstance(String operandName) { 35 | for (OperandInstance operandInstance : operandListInstance) { 36 | if (operandInstance.getName().equals(operandName)) { 37 | return operandInstance; 38 | } 39 | } 40 | throw new OperandNotFoundException("Operand name: " + operandName + ", operandListInstance: " 41 | + Arrays.toString(operandListInstance) + ", instruction: "+ this); 42 | } 43 | 44 | public Operand getOperand(String operandName) { 45 | return getOperandInstance(operandName).getOperand(); 46 | } 47 | 48 | public Operand getOperand(OperandPrototype operandPrototype) { 49 | return getOperand(operandPrototype.getName()); 50 | } 51 | 52 | private InstructionAssembler getAssembler() { 53 | return InstructionInformation.ofOperation(operation).getAssembler(); 54 | } 55 | 56 | public void allocate(AssemblyContext context) { 57 | getAssembler().allocate(this, context); 58 | } 59 | 60 | public void write(AssemblyContext context) throws AssemblerException { 61 | getAssembler().write(this, context); 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | if (operandListInstance.length == 0) { 67 | return operation.name().toLowerCase(); 68 | } else { 69 | return operation.name().toLowerCase() + " " + IoUtils.arrayToString(operandListInstance, 70 | new IoUtils.Stringifier() { 71 | @Override 72 | public String stringify(OperandInstance operandInstance) { 73 | return operandInstance.getOperand().toString(); 74 | } 75 | }, ", "); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/InstructionAssembler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public interface InstructionAssembler { 9 | 10 | void allocate(Instruction instruction, AssemblyContext context); 11 | 12 | void write(Instruction instruction, AssemblyContext context) throws AssemblerException; 13 | } 14 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/InstructionIndex.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.util.BitArray; 9 | 10 | public class InstructionIndex implements Operand, AssemblyProvider { 11 | 12 | private static final int LENGTH = 26; 13 | 14 | private BitArray value; 15 | 16 | private InstructionIndex(BitArray value) { 17 | this.value = value; 18 | } 19 | 20 | public static InstructionIndex of(int value) { 21 | return new InstructionIndex(BitArray.ofInteger(value, LENGTH)); 22 | } 23 | 24 | public BitArray getValue() { 25 | return value; 26 | } 27 | 28 | public BitArray assemble(AssemblyContext context) { 29 | return value; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Label.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.parser.Tokens; 9 | import me.zhanghai.mipsasm.util.RegexUtils; 10 | 11 | import java.util.regex.Matcher; 12 | 13 | public class Label implements Operand { 14 | 15 | private static ThreadLocal MATCHER = RegexUtils.makeThreadLocalMatcher(Tokens.IDENTIFIER_REGEX); 16 | 17 | private String name; 18 | 19 | protected Label(String name) { 20 | this.name = name; 21 | } 22 | 23 | protected static void checkName(String name) { 24 | Matcher matcher = MATCHER.get().reset(name); 25 | if (!matcher.matches()) { 26 | throw new IllegalArgumentException("Label name must match " + matcher.pattern()); 27 | } 28 | } 29 | 30 | public static Label of(String name) { 31 | checkName(name); 32 | return new Label(name); 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return name; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Offset.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.util.BitArray; 9 | 10 | public class Offset implements Operand, AssemblyProvider { 11 | 12 | private boolean isLabel; 13 | 14 | private OffsetLabel label; 15 | 16 | private Immediate immediate; 17 | 18 | public Offset(boolean isLabel, OffsetLabel label, Immediate immediate) { 19 | this.isLabel = isLabel; 20 | this.label = label; 21 | this.immediate = immediate; 22 | } 23 | 24 | public static Offset of(OffsetLabel label) { 25 | return new Offset(true, label, null); 26 | } 27 | 28 | public static Offset of(Immediate immediate) { 29 | return new Offset(false, null, immediate); 30 | } 31 | 32 | public boolean isLabel() { 33 | return isLabel; 34 | } 35 | 36 | public OffsetLabel getLabel() { 37 | if (!isLabel) { 38 | throw new IllegalStateException("Not a label: " + immediate); 39 | } 40 | return label; 41 | } 42 | 43 | public Immediate getImmediate() { 44 | if (isLabel) { 45 | throw new IllegalStateException("Not an immediate: " + label); 46 | } 47 | return immediate; 48 | } 49 | 50 | @Override 51 | public BitArray assemble(AssemblyContext context) throws AssemblerException { 52 | if (isLabel) { 53 | return label.assemble(context); 54 | } else { 55 | return immediate.assemble(context); 56 | } 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return isLabel ? label.toString() : immediate.toString(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OffsetBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class OffsetBase implements Operand { 9 | 10 | private Register base; 11 | private Immediate offset; 12 | 13 | private OffsetBase(Register base, Immediate offset) { 14 | this.base = base; 15 | this.offset = offset; 16 | } 17 | 18 | public static OffsetBase of(Register base, Immediate offset) { 19 | return new OffsetBase(base, offset); 20 | } 21 | 22 | public Register getBase() { 23 | return base; 24 | } 25 | 26 | public Immediate getOffset() { 27 | return offset; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return (offset.getValue().isZero() ? "" : offset.toString()) + "(" + base.toString() + ")"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OffsetLabel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.InternalException; 10 | import me.zhanghai.mipsasm.util.BitArray; 11 | 12 | public class OffsetLabel extends Label implements AssemblyProvider { 13 | 14 | private static final int LENGTH = Immediate.LENGTH; 15 | 16 | private OffsetLabel(String name) { 17 | super(name); 18 | } 19 | 20 | public static OffsetLabel of(String name) { 21 | checkName(name); 22 | return new OffsetLabel(name); 23 | } 24 | 25 | // From MIPS 32 manual: 26 | // An 18-bit signed offset (the 16-bit offset field shifted left 2 bits) is added to the address of the instruction 27 | // following the branch (not the branch itself), in the branch delay slot, to form a PC-relative effective target 28 | // address. 29 | @Override 30 | public BitArray assemble(AssemblyContext context) throws AssemblerException { 31 | int offset = context.getLabelAddress(this) - (context.getAddress() + Constants.BYTES_PER_INSTRUCTION); 32 | if (offset % Constants.BYTES_PER_INSTRUCTION != 0) { 33 | throw new InternalException("Instruction alignment failed, label: " + getName() + ", offset: " + offset); 34 | } 35 | offset /= Constants.BYTES_PER_INSTRUCTION; 36 | try { 37 | return BitArray.ofInteger(offset, LENGTH); 38 | } catch (IllegalArgumentException e) { 39 | throw new OffsetTooLargeException("Label name: " + getName() + ", offset: " + offset, e); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OffsetTooLargeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class OffsetTooLargeException extends AssemblerException { 9 | 10 | public OffsetTooLargeException() {} 11 | 12 | public OffsetTooLargeException(String message) { 13 | super(message); 14 | } 15 | 16 | public OffsetTooLargeException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public OffsetTooLargeException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Operand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public interface Operand {} 9 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OperandInstance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class OperandInstance extends OperandPrototype { 9 | 10 | private Operand operand; 11 | 12 | private OperandInstance(String name, OperandType type, Operand operand) { 13 | super(name, type); 14 | 15 | this.operand = operand; 16 | } 17 | 18 | public static OperandInstance fromPrototype(OperandPrototype operandPrototype, Operand operand) { 19 | return new OperandInstance(operandPrototype.getName(), operandPrototype.getType(), operand); 20 | } 21 | 22 | public Operand getOperand() { 23 | return operand; 24 | } 25 | 26 | @Override 27 | public boolean equals(Object object) { 28 | if (this == object) { 29 | return true; 30 | } else if (object == null || getClass() != object.getClass()) { 31 | return false; 32 | } else if (!super.equals(object)) { 33 | return false; 34 | } 35 | 36 | OperandInstance that = (OperandInstance) object; 37 | return operand.equals(that.operand); 38 | } 39 | 40 | @Override 41 | public int hashCode() { 42 | int result = super.hashCode(); 43 | result = 31 * result + operand.hashCode(); 44 | return result; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "OperandInstance {" + 50 | "operand=" + operand + 51 | "} " + super.toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OperandListPrototypes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class OperandListPrototypes { 9 | 10 | public static final OperandPrototype[] EMPTY = new OperandPrototype[] {}; 11 | 12 | public static final OperandPrototype[] DESTINATION_SOURCE_SOURCE2 = new OperandPrototype[] { 13 | OperandPrototypes.DESTINATION, 14 | OperandPrototypes.SOURCE, 15 | OperandPrototypes.SOURCE2 16 | }; 17 | 18 | public static final OperandPrototype[] SOURCE2_SOURCE_IMMEDIATE = new OperandPrototype[] { 19 | OperandPrototypes.SOURCE2, 20 | OperandPrototypes.SOURCE, 21 | OperandPrototypes.IMMEDIATE 22 | }; 23 | 24 | public static final OperandPrototype[] OFFSET = new OperandPrototype[] { 25 | OperandPrototypes.OFFSET 26 | }; 27 | 28 | public static final OperandPrototype[] SOURCE_SOURCE2_OFFSET = new OperandPrototype[] { 29 | OperandPrototypes.SOURCE, 30 | OperandPrototypes.SOURCE2, 31 | OperandPrototypes.OFFSET 32 | }; 33 | 34 | public static final OperandPrototype[] SOURCE_OFFSET = new OperandPrototype[] { 35 | OperandPrototypes.SOURCE, 36 | OperandPrototypes.OFFSET 37 | }; 38 | 39 | public static final OperandPrototype[] COPROCESSOR_FUNCTION = new OperandPrototype[] { 40 | OperandPrototypes.COPROCESSOR_FUNCTION 41 | }; 42 | 43 | public static final OperandPrototype[] SOURCE_SOURCE2 = new OperandPrototype[] { 44 | OperandPrototypes.SOURCE, 45 | OperandPrototypes.SOURCE2 46 | }; 47 | 48 | public static final OperandPrototype[] DESTINATION_SOURCE2_SHIFT_AMOUNT = new OperandPrototype[] { 49 | OperandPrototypes.DESTINATION, 50 | OperandPrototypes.SOURCE2, 51 | OperandPrototypes.SHIFT_AMOUNT 52 | }; 53 | 54 | public static final OperandPrototype[] DESTINATION_SOURCE2_SOURCE = new OperandPrototype[] { 55 | OperandPrototypes.DESTINATION, 56 | OperandPrototypes.SOURCE2, 57 | OperandPrototypes.SOURCE 58 | }; 59 | 60 | public static final OperandPrototype[] TARGET = new OperandPrototype[] { 61 | OperandPrototypes.TARGET 62 | }; 63 | 64 | public static final OperandPrototype[] DESTINATION_SOURCE = new OperandPrototype[] { 65 | OperandPrototypes.DESTINATION, 66 | OperandPrototypes.SOURCE 67 | }; 68 | 69 | public static final OperandPrototype[] SOURCE = new OperandPrototype[] { 70 | OperandPrototypes.SOURCE 71 | }; 72 | 73 | public static final OperandPrototype[] SOURCE2_OFFSET_BASE = new OperandPrototype[] { 74 | OperandPrototypes.SOURCE2, 75 | OperandPrototypes.OFFSET_BASE 76 | }; 77 | 78 | public static final OperandPrototype[] SOURCE2_IMMEDIATE = new OperandPrototype[] { 79 | OperandPrototypes.SOURCE2, 80 | OperandPrototypes.IMMEDIATE 81 | }; 82 | 83 | public static final OperandPrototype[] SOURCE2_DESTINATION = new OperandPrototype[] { 84 | OperandPrototypes.SOURCE2, 85 | OperandPrototypes.DESTINATION 86 | }; 87 | 88 | public static final OperandPrototype[] DESTINATION = new OperandPrototype[] { 89 | OperandPrototypes.DESTINATION 90 | }; 91 | 92 | public static final OperandPrototype[] HINT_OFFSET_BASE = new OperandPrototype[] { 93 | OperandPrototypes.HINT, 94 | OperandPrototypes.OFFSET_BASE 95 | }; 96 | 97 | public static final OperandPrototype[] SOURCE2_WORD_IMMEDIATE = new OperandPrototype[] { 98 | OperandPrototypes.SOURCE2, 99 | OperandPrototypes.WORD_IMMEDIATE 100 | }; 101 | 102 | public static final OperandPrototype[] SOURCE2_LABEL = new OperandPrototype[] { 103 | OperandPrototypes.SOURCE2, 104 | OperandPrototypes.LABEL 105 | }; 106 | } 107 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OperandNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.InternalException; 9 | 10 | public class OperandNotFoundException extends InternalException { 11 | 12 | public OperandNotFoundException() {} 13 | 14 | public OperandNotFoundException(String message) { 15 | super(message); 16 | } 17 | 18 | public OperandNotFoundException(String message, Throwable cause) { 19 | super(message, cause); 20 | } 21 | 22 | public OperandNotFoundException(Throwable cause) { 23 | super(cause); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OperandPrototype.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class OperandPrototype { 9 | 10 | private String name; 11 | private OperandType type; 12 | 13 | protected OperandPrototype(String name, OperandType type) { 14 | this.name = name; 15 | this.type = type; 16 | } 17 | 18 | public static OperandPrototype of(String name, OperandType type) { 19 | return new OperandPrototype(name, type); 20 | } 21 | 22 | public String getName() { 23 | return name; 24 | } 25 | 26 | public OperandType getType() { 27 | return type; 28 | } 29 | 30 | @Override 31 | public boolean equals(Object object) { 32 | 33 | if (this == object) { 34 | return true; 35 | } else if (object == null || getClass() != object.getClass()) { 36 | return false; 37 | } 38 | 39 | OperandPrototype that = (OperandPrototype) object; 40 | if (!name.equals(that.name)) { 41 | return false; 42 | } else if (type != that.type) { 43 | return false; 44 | } 45 | 46 | return true; 47 | } 48 | 49 | @Override 50 | public int hashCode() { 51 | int result = name.hashCode(); 52 | result = 31 * result + type.hashCode(); 53 | return result; 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "OperandPrototype {" + 59 | "name='" + name + "'" + 60 | ", type=" + type + 61 | '}'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OperandPrototypes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class OperandPrototypes { 9 | 10 | private OperandPrototypes() {} 11 | 12 | public static final OperandPrototype DESTINATION = OperandPrototype.of("destination", OperandType.REGISTER); 13 | 14 | public static final OperandPrototype SOURCE2 = OperandPrototype.of("source2", OperandType.REGISTER); 15 | 16 | public static final OperandPrototype SOURCE = OperandPrototype.of("source", OperandType.REGISTER); 17 | 18 | public static final OperandPrototype IMMEDIATE = OperandPrototype.of("immediate", OperandType.IMMEDIATE); 19 | 20 | public static final OperandPrototype OFFSET = OperandPrototype.of("offset", OperandType.OFFSET); 21 | 22 | public static final OperandPrototype COPROCESSOR_FUNCTION = OperandPrototype.of("coprocessorFunction", OperandType.COPROCESSOR_FUNCTION); 23 | 24 | public static final OperandPrototype SHIFT_AMOUNT = OperandPrototype.of("shiftAmount", OperandType.SHIFT_AMOUNT); 25 | 26 | public static final OperandPrototype TARGET = OperandPrototype.of("target", OperandType.TARGET); 27 | 28 | public static final OperandPrototype OFFSET_BASE = OperandPrototype.of("offset(base)", OperandType.OFFSET_BASE); 29 | 30 | public static final OperandPrototype HINT = OperandPrototype.of("hint", OperandType.REGISTER); 31 | 32 | public static final OperandPrototype WORD_IMMEDIATE = OperandPrototype.of("wordImmediate", OperandType.WORD_IMMEDIATE); 33 | 34 | public static final OperandPrototype LABEL = OperandPrototype.of("label", OperandType.LABEL); 35 | } 36 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/OperandType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public enum OperandType { 9 | REGISTER, 10 | IMMEDIATE, 11 | OFFSET, 12 | COPROCESSOR_FUNCTION, 13 | SHIFT_AMOUNT, 14 | TARGET, 15 | OFFSET_BASE, 16 | WORD_IMMEDIATE, 17 | LABEL 18 | } 19 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Operation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.InternalException; 9 | import me.zhanghai.mipsasm.util.BitArray; 10 | 11 | // FIXME: In fact, Operation should not be abstracted like this. Due to some corner cases, we need dynamic abstractions, 12 | // like OperandPrototype and OperandInstance, and in this case template and instance. 13 | public enum Operation { 14 | 15 | ADD(Codes.SPECIAL, 0b100000), 16 | ADDI(0b001000), 17 | ADDIU(0b001001), 18 | ADDU(Codes.SPECIAL, 0b100001), 19 | AND(Codes.SPECIAL, 0b100100), 20 | ANDI(0b001100), 21 | B, 22 | // BAL, BC1F, BC1FL, ... , BC2TL 23 | BEQ(0b000100), 24 | BEQL(0b010100), 25 | BGEZ(Codes.REGIMM, 0b00001, true), 26 | BGEZAL(Codes.REGIMM, 0b10001, true), 27 | BGEZALL(Codes.REGIMM, 0b10011, true), 28 | BGEZL(Codes.REGIMM, 0b00011, true), 29 | BGTZ(0b000111, 0b00000, true), 30 | BGTZL(0b010111, 0b00000, true), 31 | BLEZ(0b000110, 0b00000, true), 32 | BLEZL(0b010110, 0b00000, true), 33 | BLTZ(Codes.REGIMM, 0b00000, true), 34 | BLTZAL(Codes.REGIMM, 0b10000, true), 35 | BLTZALL(Codes.REGIMM, 0b10010, true), 36 | BLTZL(Codes.REGIMM, 0b00010, true), 37 | BNE(0b000101), 38 | BNEL(0b010101), 39 | BREAK(Codes.SPECIAL, 0b001101), 40 | // C, ... , CLZ 41 | COP2(Codes.COP2), 42 | // CTC, ... , DERET 43 | DERET(Codes.COP0, 0b011111), 44 | DIV(Codes.SPECIAL, 0b011010), 45 | DIVU(Codes.SPECIAL, 0b011011), 46 | ERET(Codes.COP0, 0b011000), 47 | J(0b000010), 48 | JAL(0b000011), 49 | JALR(Codes.SPECIAL, 0b001001), 50 | JR(Codes.SPECIAL, 0b001000), 51 | LA, 52 | LB(0b100000), 53 | LBU(0b100100), 54 | LDC1(0b110101), 55 | LDC2(0b110110), 56 | LH(0b100001), 57 | LHU(0b100101), 58 | LI, 59 | LL(0b110000), 60 | LUI(0b001111), 61 | LW(0b100011), 62 | LWC1(0b110001), 63 | LWC2(0b110010), 64 | // LWC3(0b110011), 65 | LWL(0b100010), 66 | LWR(0b100110), 67 | // MADD, ... MFC2 68 | MFC0(Codes.COP0, 0b00000, false), 69 | MFHI(Codes.SPECIAL, 0b010000), 70 | MFLO(Codes.SPECIAL, 0b010010), 71 | MOVE, 72 | MOVN(Codes.SPECIAL, 0b001011), 73 | // MOVT 74 | MOVZ(Codes.SPECIAL, 0b001010), 75 | // MSUB, ... ,MTC2 76 | MTC0(Codes.COP0, 0b00100, false), 77 | MTHI(Codes.SPECIAL, 0b010001), 78 | MTLO(Codes.SPECIAL, 0b010011), 79 | // MUL 80 | MULT(Codes.SPECIAL, 0b011000), 81 | MULTU(Codes.SPECIAL, 0b011001), 82 | NOR(Codes.SPECIAL, 0b100111), 83 | NOP(), 84 | OR(Codes.SPECIAL, 0b100101), 85 | ORI(0b001101), 86 | PREF(0b110011), 87 | SB(0b101000), 88 | SC(0b111000), 89 | // SDBBP 90 | SDC1(0b111101), 91 | SDC2(0b111110), 92 | // SDL(0b101100), 93 | // SDR(0b101101), 94 | SH(0b101001), 95 | SLL(Codes.SPECIAL, 0b000000), 96 | SLLV(Codes.SPECIAL, 0b000100), 97 | SLT(Codes.SPECIAL, 0b101010), 98 | SLTI(0b001010), 99 | SLTIU(0b001011), 100 | SLTU(Codes.SPECIAL, 0b101011), 101 | SRA(Codes.SPECIAL, 0b000011), 102 | SRAV(Codes.SPECIAL, 0b000111), 103 | SRL(Codes.SPECIAL, 0b000010), 104 | SRLV(Codes.SPECIAL, 0b000110), 105 | // SSNOP 106 | SUB(Codes.SPECIAL, 0b100010), 107 | SUBU(Codes.SPECIAL, 0b100011), 108 | SW(0b101011), 109 | SWC1(0b111001), 110 | SWC2(0b111010), 111 | SWC3(0b111011), 112 | SWL(0b101010), 113 | SWR(0b101110), 114 | TLBP(Codes.COP0, 0b001000), 115 | TLBR(Codes.COP0, 0b000001), 116 | TLBWI(Codes.COP0, 0b000010), 117 | TLBWR(Codes.COP0, 0b000110), 118 | // TEQ, ... , TNEI 119 | SYSCALL(Codes.SPECIAL, 0b001100), 120 | WAIT(Codes.COP0, 0b100000), 121 | XOR(Codes.SPECIAL, 0b100110), 122 | XORI(0b001110); 123 | 124 | private static final int CODE_LENGTH = 6; 125 | private static final int FUNCTION_LENGTH = 6; 126 | private static final int SOURCE_LENGTH = 5; 127 | private static final int SOURCE2_LENGTH = 5; 128 | 129 | private BitArray code; 130 | private BitArray function; 131 | private BitArray source; 132 | private BitArray source2; 133 | 134 | private interface Codes { 135 | int SPECIAL = 0b000000; 136 | int REGIMM = 0b000001; 137 | int COP0 = 0b010000; 138 | int COP1 = 0b010001; 139 | int COP2 = 0b010010; 140 | } 141 | 142 | Operation(BitArray code, BitArray source, BitArray source2, BitArray function) { 143 | this.code = code; 144 | this.function = function; 145 | this.source = source; 146 | this.source2 = source2; 147 | } 148 | 149 | Operation(int code, int source, boolean isSource2) { 150 | this(BitArray.of(code, CODE_LENGTH), isSource2 ? null : BitArray.of(source, SOURCE_LENGTH), 151 | isSource2 ? BitArray.of(source, SOURCE2_LENGTH) : null, null); 152 | } 153 | 154 | Operation(int code, int function) { 155 | this(BitArray.of(code, CODE_LENGTH), null, null, BitArray.of(function, FUNCTION_LENGTH)); 156 | } 157 | 158 | Operation(int code) { 159 | this(BitArray.of(code, CODE_LENGTH), null, null, null); 160 | } 161 | 162 | Operation() { 163 | this(null, null, null, null); 164 | } 165 | 166 | public static Operation of(BitArray code, BitArray source, BitArray source2, BitArray function) { 167 | for (Operation operation : values()) { 168 | if ((operation.code != null && operation.code.equals(code)) 169 | && (operation.source == null || operation.source.equals(source)) 170 | && (operation.source2 == null || operation.source2.equals(source2)) 171 | && (operation.function == null || operation.function.equals(function))) { 172 | return operation; 173 | } 174 | } 175 | throw new IllegalArgumentException("Unknown operation, code: " + code + ", source: " + source + ", source2: " 176 | + source2 + ", function: " + function); 177 | } 178 | 179 | public BitArray getCode() { 180 | if (code == null) { 181 | throw new InternalException(new IllegalStateException("getCode() called on an Operation without a code")); 182 | } 183 | return code; 184 | } 185 | 186 | public BitArray getSource() { 187 | if (source == null) { 188 | throw new InternalException(new IllegalStateException( 189 | "getSource() called on an Operation without a source")); 190 | } 191 | return source; 192 | } 193 | 194 | public BitArray getSource2() { 195 | if (source2 == null) { 196 | throw new InternalException(new IllegalStateException( 197 | "getSource2() called on an Operation without a source2")); 198 | } 199 | return source2; 200 | } 201 | 202 | public BitArray getFunction() { 203 | if (function == null) { 204 | throw new InternalException(new IllegalStateException( 205 | "getFunction() called on an Operation without a function")); 206 | } 207 | return function; 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Register.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.util.BitArray; 9 | 10 | public enum Register implements Operand, AssemblyProvider { 11 | 12 | ZERO, 13 | AT, 14 | V0, 15 | V1, 16 | A0, 17 | A1, 18 | A2, 19 | A3, 20 | T0, 21 | T1, 22 | T2, 23 | T3, 24 | T4, 25 | T5, 26 | T6, 27 | T7, 28 | S0, 29 | S1, 30 | S2, 31 | S3, 32 | S4, 33 | S5, 34 | S6, 35 | S7, 36 | T8, 37 | T9, 38 | K0, 39 | K1, 40 | GP, 41 | SP, 42 | FP, 43 | RA; 44 | 45 | private static final int LENGTH = 5; 46 | 47 | public static Register of(int index) { 48 | return values()[index]; 49 | } 50 | 51 | public BitArray assemble(AssemblyContext context) { 52 | return BitArray.of(ordinal(), LENGTH); 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "$" + name().toLowerCase(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/ShiftAmount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.util.BitArray; 9 | 10 | public class ShiftAmount implements Operand, AssemblyProvider { 11 | 12 | private static final int LENGTH = 5; 13 | 14 | public static final ShiftAmount ZERO = ShiftAmount.of(0); 15 | 16 | private BitArray value; 17 | 18 | private ShiftAmount(BitArray value) { 19 | this.value = value; 20 | } 21 | 22 | public static ShiftAmount of(BitArray value) { 23 | if (value.length() != LENGTH) { 24 | throw new IllegalArgumentException("Shift amount length != " + LENGTH + ": " + value.length()); 25 | } 26 | return new ShiftAmount(BitArray.copyOf(value)); 27 | } 28 | 29 | public static ShiftAmount of(int value) { 30 | return new ShiftAmount(BitArray.of(value, LENGTH)); 31 | } 32 | 33 | public BitArray assemble(AssemblyContext context) { 34 | return value; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return value.toDecimalString(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/SpaceDirective.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class SpaceDirective extends Directive { 9 | 10 | private int length; 11 | 12 | private SpaceDirective(int length) { 13 | this.length = length; 14 | } 15 | 16 | public static SpaceDirective of(int length) { 17 | return new SpaceDirective(length); 18 | } 19 | 20 | public int getLength() { 21 | return length; 22 | } 23 | 24 | @Override 25 | public void allocate(AssemblyContext context) { 26 | context.allocateSpace(length); 27 | } 28 | 29 | @Override 30 | public void write(AssemblyContext context) throws AssemblerException { 31 | context.writeSpace(length); 32 | } 33 | 34 | @Override 35 | public boolean equals(Object object) { 36 | 37 | if (this == object) { 38 | return true; 39 | } else if (object == null || getClass() != object.getClass()) { 40 | return false; 41 | } 42 | 43 | SpaceDirective that = (SpaceDirective) object; 44 | return length == that.length; 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return length; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "." + DirectiveInformation.SPACE.name().toLowerCase() + " " + length; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/StorageDirective.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.InternalException; 10 | import me.zhanghai.mipsasm.util.BitArray; 11 | 12 | public class StorageDirective extends Directive { 13 | 14 | private BitArray value; 15 | 16 | private StorageDirective(BitArray value) { 17 | this.value = value; 18 | } 19 | 20 | public static StorageDirective of(BitArray value) { 21 | if (value.length() % Constants.BYTE_LENGTH != 0) { 22 | throw new IllegalArgumentException("Storage directive length not in bytes: " + value.length()); 23 | } 24 | return new StorageDirective(BitArray.copyOf(value)); 25 | } 26 | 27 | public static StorageDirective of(int value, int length) { 28 | return of(BitArray.of(value, length)); 29 | } 30 | 31 | public BitArray getValue() { 32 | return value; 33 | } 34 | 35 | @Override 36 | public void allocate(AssemblyContext context) { 37 | context.allocateBits(value.length()); 38 | } 39 | 40 | @Override 41 | public void write(AssemblyContext context) throws AssemblerException { 42 | context.writeBytes(value); 43 | } 44 | 45 | @Override 46 | public boolean equals(Object object) { 47 | 48 | if (this == object) { 49 | return true; 50 | } if (object == null || getClass() != object.getClass()) { 51 | return false; 52 | } 53 | 54 | StorageDirective storage = (StorageDirective) object; 55 | return value.equals(storage.value); 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | return value.hashCode(); 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | StringBuilder builder = new StringBuilder("."); 66 | switch (value.length()) { 67 | case Constants.BYTE_LENGTH: 68 | builder.append(DirectiveInformation.BYTE.name().toLowerCase()); 69 | break; 70 | case Constants.HALF_WORD_LENGTH: 71 | builder.append(DirectiveInformation.HALF.name().toLowerCase()); 72 | break; 73 | case Constants.WORD_LENGTH: 74 | builder.append(DirectiveInformation.WORD.name().toLowerCase()); 75 | break; 76 | default: 77 | throw new InternalException("Illegal storage directive length: " + value.length()); 78 | } 79 | builder.append(" ") 80 | .append(value.toHexString()); 81 | return builder.toString(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/Target.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.util.BitArray; 9 | 10 | public class Target implements Operand, AssemblyProvider { 11 | 12 | private boolean isLabel; 13 | 14 | private TargetLabel label; 15 | 16 | private InstructionIndex instructionIndex; 17 | 18 | public Target(boolean isLabel, TargetLabel label, InstructionIndex instructionIndex) { 19 | this.isLabel = isLabel; 20 | this.label = label; 21 | this.instructionIndex = instructionIndex; 22 | } 23 | 24 | public static Target of(TargetLabel label) { 25 | return new Target(true, label, null); 26 | } 27 | 28 | public static Target of(InstructionIndex instructionIndex) { 29 | return new Target(false, null, instructionIndex); 30 | } 31 | 32 | public boolean isLabel() { 33 | return isLabel; 34 | } 35 | 36 | public TargetLabel getLabel() { 37 | if (!isLabel) { 38 | throw new IllegalStateException("Not a label: " + instructionIndex); 39 | } 40 | return label; 41 | } 42 | 43 | public InstructionIndex getInstructionIndex() { 44 | if (isLabel) { 45 | throw new IllegalStateException("Not an instruction index: " + label); 46 | } 47 | return instructionIndex; 48 | } 49 | 50 | @Override 51 | public BitArray assemble(AssemblyContext context) throws AssemblerException { 52 | if (isLabel) { 53 | return label.assemble(context); 54 | } else { 55 | return instructionIndex.assemble(context); 56 | } 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return isLabel ? label.toString() : instructionIndex.toString(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/TargetLabel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.InternalException; 10 | import me.zhanghai.mipsasm.util.BitArray; 11 | 12 | public class TargetLabel extends Label implements AssemblyProvider { 13 | 14 | private static final int LENGTH = 26; 15 | 16 | private TargetLabel(String name) { 17 | super(name); 18 | } 19 | 20 | public static TargetLabel of(String name) { 21 | checkName(name); 22 | return new TargetLabel(name); 23 | } 24 | 25 | // From MIPS 32 manual: 26 | // The low 28 bits of the target address is the instr_index field shifted left 2 bits. 27 | // The remaining upper bits are the corresponding bits of the address of the instruction in the delay slot (not 28 | // the branch itself). 29 | @Override 30 | public BitArray assemble(AssemblyContext context) throws AssemblerException { 31 | BitArray address = BitArray.of(context.getLabelAddress(this), Constants.ADDRESS_LENGTH); 32 | if (address.get(0) || address.get(1)) { 33 | throw new InternalException("Instruction alignment failed, label: " + getName() + ", address: " + address); 34 | } 35 | // TODO: NOP for delay slot is not implemented here. 36 | if (!address.subArray(2 + LENGTH, Constants.ADDRESS_LENGTH).equals( 37 | BitArray.of(context.getAddress() + Constants.BYTES_PER_INSTRUCTION, 2 + LENGTH, 38 | Constants.ADDRESS_LENGTH))) { 39 | throw new OffsetTooLargeException("Label name: " + getName() + ", address: " + address 40 | + ", current address: " + BitArray.of(context.getAddress(), Constants.ADDRESS_LENGTH)); 41 | } 42 | return address 43 | .rightShift(2) 44 | .setLength(LENGTH); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/TextDirective.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class TextDirective extends Directive { 9 | 10 | private WordImmediate address; 11 | 12 | private TextDirective(WordImmediate address) { 13 | this.address = address; 14 | } 15 | 16 | public static TextDirective of(WordImmediate address) { 17 | return new TextDirective(address); 18 | } 19 | 20 | public WordImmediate getAddress() { 21 | return address; 22 | } 23 | 24 | @Override 25 | public void allocate(AssemblyContext context) { 26 | context.allocateToAddress(address); 27 | } 28 | 29 | @Override 30 | public void write(AssemblyContext context) throws AssemblerException { 31 | context.writeToAddress(address); 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "." + DirectiveInformation.TEXT.name().toLowerCase() + " " + address; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/UndefinedLabelException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | public class UndefinedLabelException extends AssemblerException { 9 | 10 | public UndefinedLabelException() {} 11 | 12 | public UndefinedLabelException(String message) { 13 | super(message); 14 | } 15 | 16 | public UndefinedLabelException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public UndefinedLabelException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/assembler/WordImmediate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.assembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.util.BitArray; 10 | 11 | public class WordImmediate implements Operand { 12 | 13 | private BitArray value; 14 | 15 | private WordImmediate(BitArray value) { 16 | this.value = value; 17 | } 18 | 19 | public static WordImmediate of(int value) { 20 | return new WordImmediate(BitArray.of(value, Constants.WORD_LENGTH)); 21 | } 22 | 23 | public BitArray getValue() { 24 | return value; 25 | } 26 | 27 | public BitArray getLower() { 28 | return value.subArray(0, Constants.HALF_WORD_LENGTH); 29 | } 30 | 31 | public BitArray getUpper() { 32 | return value.subArray(Constants.HALF_WORD_LENGTH); 33 | } 34 | 35 | @Override 36 | public boolean equals(Object object) { 37 | 38 | if (this == object) { 39 | return true; 40 | } if (object == null || getClass() != object.getClass()) { 41 | return false; 42 | } 43 | 44 | WordImmediate that = (WordImmediate) object; 45 | return value.equals(that.value); 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return value.hashCode(); 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return value.toHexString(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/CoeReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | import me.zhanghai.mipsasm.util.IoUtils; 9 | import me.zhanghai.mipsasm.util.RegexUtils; 10 | import me.zhanghai.mipsasm.util.UnsignedCompat; 11 | 12 | import java.io.ByteArrayInputStream; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.util.regex.Matcher; 16 | import java.util.regex.Pattern; 17 | 18 | public class CoeReader { 19 | 20 | private static String GROUP_RADIX = "radix"; 21 | private static ThreadLocal RADIX_MATCHER = 22 | RegexUtils.makeThreadLocalMatcher("memory_initialization_radix\\s*=\\s*(?<" + GROUP_RADIX + ">.*?)\\s*;"); 23 | 24 | private static String GROUP_VECTOR = "vector"; 25 | private static ThreadLocal VECTOR_MATCHER = RegexUtils.makeThreadLocalMatcher( 26 | "memory_initialization_vector\\s*=\\s*(?<" + GROUP_VECTOR + ">.*?)\\s*;", Pattern.DOTALL); 27 | 28 | private static ThreadLocal VECTOR_IGNORE_MATCHER = RegexUtils.makeThreadLocalMatcher("[,\\s]+"); 29 | 30 | public static ByteArrayInputStream coeToBytes(InputStream inputStream) throws IOException, CoeReaderException { 31 | 32 | String input = IoUtils.inputStreamToString(inputStream).toLowerCase(); 33 | Matcher radixMatcher = RADIX_MATCHER.get().reset(input); 34 | if (!radixMatcher.find()) { 35 | throw new CoeReaderException("Radix not found"); 36 | } 37 | int radix; 38 | try { 39 | radix = Integer.parseInt(radixMatcher.group(GROUP_RADIX)); 40 | } catch (NumberFormatException e) { 41 | throw new CoeReaderException("Cannot parse radix", e); 42 | } 43 | Matcher vectorMatcher = VECTOR_MATCHER.get().reset(input); 44 | if (!vectorMatcher.find()) { 45 | throw new CoeReaderException("Vector not found"); 46 | } 47 | String vector = vectorMatcher.group(GROUP_VECTOR); 48 | Matcher vectorIgnoreMatcher = VECTOR_IGNORE_MATCHER.get().reset(vector); 49 | vector = vectorIgnoreMatcher.replaceAll(""); 50 | 51 | byte[] bytes; 52 | switch (radix) { 53 | case 2: 54 | bytes = new byte[(int) Math.ceil(vector.length() / 8d)]; 55 | for (int i = 0, j = 0, k = 8; j < vector.length(); ++i, j = k, k += 8) { 56 | if (k > vector.length()) { 57 | k = vector.length(); 58 | } 59 | bytes[i] = UnsignedCompat.parseUnsignedByte(vector.substring(j, k), radix); 60 | } 61 | break; 62 | case 16: 63 | bytes = new byte[(int) Math.ceil(vector.length() / 2d)]; 64 | for (int i = 0, j = 0, k = 2; j < vector.length(); ++i, j = k, k += 2) { 65 | if (k > vector.length()) { 66 | k = vector.length(); 67 | } 68 | bytes[i] = UnsignedCompat.parseUnsignedByte(vector.substring(j, k), radix); 69 | } 70 | break; 71 | default: 72 | throw new CoeReaderException("Unsupported radix: " + radix); 73 | } 74 | return new ByteArrayInputStream(bytes); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/CoeReaderException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | public class CoeReaderException extends Exception { 9 | 10 | public CoeReaderException() {} 11 | 12 | public CoeReaderException(String message) { 13 | super(message); 14 | } 15 | 16 | public CoeReaderException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public CoeReaderException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/Disassembler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.Assemblable; 10 | import me.zhanghai.mipsasm.util.BitArray; 11 | import me.zhanghai.mipsasm.util.IoUtils; 12 | 13 | import java.io.*; 14 | import java.nio.charset.StandardCharsets; 15 | import java.util.Map; 16 | 17 | public class Disassembler { 18 | 19 | public static void disassemble(InputStream inputStream, OutputStream outputStream) 20 | throws DisassemblerException { 21 | 22 | DisassemblyContext context = new DisassemblyContext(); 23 | 24 | BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); 25 | while (true) { 26 | BitArray bitArray; 27 | try { 28 | bitArray = IoUtils.readBitArray(bufferedInputStream); 29 | } catch (IOException e) { 30 | throw new DisassemblerException("Error reading", e); 31 | } 32 | if (bitArray == null) { 33 | break; 34 | } 35 | // 0 can be sll $zero, $zero, 0, making all spacing instructions. In this case we prefer interpreting it as 36 | // spacing. 37 | if (bitArray.length() == Constants.WORD_LENGTH && !bitArray.isZero()) { 38 | WordDisassembler.disassemble(bitArray, context); 39 | } else { 40 | StorageDirectiveDisassembler.disassemble(bitArray, context); 41 | } 42 | } 43 | context.packStorageDirective(); 44 | 45 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); 46 | for (Map.Entry entry : context.getAddressAssemblableMap().entrySet()) { 47 | Integer address = entry.getKey(); 48 | String label = context.getLabel(address); 49 | if (label != null) { 50 | try { 51 | writer.write(label); 52 | writer.write(":"); 53 | writer.newLine(); 54 | } catch (IOException e) { 55 | throw new DisassemblerException("Error writing label: " + label, e); 56 | } 57 | } 58 | Assemblable assemblable = entry.getValue(); 59 | String assemblableString = assemblable.toString(); 60 | try { 61 | writer.write(assemblableString); 62 | writer.newLine(); 63 | } catch (IOException e) { 64 | throw new DisassemblerException("Error writing assemblable: " + assemblableString, e); 65 | } 66 | } 67 | try { 68 | writer.flush(); 69 | } catch (IOException e) { 70 | throw new DisassemblerException("Error writing", e); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/DisassemblerException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | public class DisassemblerException extends Exception { 9 | 10 | public DisassemblerException() {} 11 | 12 | public DisassemblerException(String message) { 13 | super(message); 14 | } 15 | 16 | public DisassemblerException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public DisassemblerException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/DisassemblyContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.Assemblable; 10 | import me.zhanghai.mipsasm.assembler.SpaceDirective; 11 | import me.zhanghai.mipsasm.assembler.StorageDirective; 12 | import me.zhanghai.mipsasm.util.BitArray; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.NavigableMap; 17 | import java.util.TreeMap; 18 | 19 | public class DisassemblyContext { 20 | 21 | private Integer labelIndex = 0; 22 | 23 | private NavigableMap addressLabelMap = new TreeMap<>(); 24 | 25 | // WONTFIX: Maximum address can be checked when addLabel() is called, however this adds the overhead of knowing the 26 | // length of the input stream during the first pass. 27 | private Integer address = 0; 28 | 29 | private NavigableMap addressAssemblableMap = new TreeMap<>(); 30 | 31 | private String makeLabelName() { 32 | String name = "label_" + labelIndex; 33 | ++labelIndex; 34 | return name; 35 | } 36 | 37 | public String addLabel(Integer address) { 38 | String name = addressLabelMap.get(address); 39 | if (name != null) { 40 | return name; 41 | } 42 | name = makeLabelName(); 43 | addressLabelMap.put(address, name); 44 | return name; 45 | } 46 | 47 | public NavigableMap getAddressLabelMap() { 48 | return addressLabelMap; 49 | } 50 | 51 | public String getLabel(Integer address) { 52 | return addressLabelMap.get(address); 53 | } 54 | 55 | public NavigableMap getAddressAssemblableMap() { 56 | return addressAssemblableMap; 57 | } 58 | 59 | public Integer getAddress() { 60 | return address; 61 | } 62 | 63 | public void appendAssemblable(Assemblable assemblable, int length) { 64 | addressAssemblableMap.put(address, assemblable); 65 | address += length; 66 | } 67 | 68 | private boolean isByteStorageDirective(Assemblable assemblable) { 69 | return assemblable != null && assemblable instanceof StorageDirective 70 | && ((StorageDirective) assemblable).getValue().length() == Constants.BYTE_LENGTH; 71 | } 72 | 73 | private void packByteStorageDirective() { 74 | 75 | for (Integer address1 = addressAssemblableMap.firstKey(); address1 != null; 76 | address1 = addressAssemblableMap.higherKey(address1)) { 77 | 78 | if (address1 % Constants.BYTES_PER_WORD != 0) { 79 | continue; 80 | } 81 | Assemblable assemblable1 = addressAssemblableMap.get(address1); 82 | if (!isByteStorageDirective(assemblable1)) { 83 | continue; 84 | } 85 | Integer address2 = address1 + 1; 86 | if (addressLabelMap.containsKey(address2)) { 87 | continue; 88 | } 89 | Assemblable assemblable2 = addressAssemblableMap.get(address2); 90 | if (!isByteStorageDirective(assemblable2)) { 91 | continue; 92 | } 93 | Integer address3 = address2 + 1; 94 | if (addressLabelMap.containsKey(address3)) { 95 | continue; 96 | } 97 | Assemblable assemblable3 = addressAssemblableMap.get(address3); 98 | if (!isByteStorageDirective(assemblable3)) { 99 | continue; 100 | } 101 | Integer address4 = address3 + 1; 102 | if (addressLabelMap.containsKey(address4)) { 103 | continue; 104 | } 105 | Assemblable assemblable4 = addressAssemblableMap.get(address4); 106 | if (!isByteStorageDirective(assemblable4)) { 107 | continue; 108 | } 109 | 110 | StorageDirective storageDirective = StorageDirective.of(BitArray.of( 111 | ((StorageDirective) assemblable1).getValue(), 112 | ((StorageDirective) assemblable2).getValue(), 113 | ((StorageDirective) assemblable3).getValue(), 114 | ((StorageDirective) assemblable4).getValue())); 115 | addressAssemblableMap.put(address1, storageDirective); 116 | addressAssemblableMap.remove(address2); 117 | addressAssemblableMap.remove(address3); 118 | addressAssemblableMap.remove(address4); 119 | } 120 | } 121 | 122 | private boolean isZeroWordStorageDirective(Assemblable assemblable) { 123 | if (assemblable != null && assemblable instanceof StorageDirective) { 124 | BitArray value = ((StorageDirective) assemblable).getValue(); 125 | if (value.length() == Constants.WORD_LENGTH && value.isZero()) { 126 | return true; 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | private void packZeroWordStorageDirective() { 133 | 134 | List addressList = new ArrayList<>(); 135 | 136 | for (Integer address = addressAssemblableMap.firstKey(); address != null; 137 | address = addressAssemblableMap.higherKey(address)) { 138 | 139 | if ((addressList.isEmpty() || !addressLabelMap.containsKey(address)) 140 | && isZeroWordStorageDirective(addressAssemblableMap.get(address))) { 141 | addressList.add(address); 142 | continue; 143 | } 144 | 145 | if (addressList.size() > 1) { 146 | for (Integer listAddress : addressList) { 147 | addressAssemblableMap.remove(listAddress); 148 | } 149 | addressAssemblableMap.put(addressList.get(0), 150 | SpaceDirective.of(Constants.BYTES_PER_WORD * addressList.size())); 151 | } 152 | addressList.clear(); 153 | 154 | if (isZeroWordStorageDirective(addressAssemblableMap.get(address))) { 155 | addressList.add(address); 156 | } 157 | } 158 | if (addressList.size() > 1) { 159 | for (Integer listAddress : addressList) { 160 | addressAssemblableMap.remove(listAddress); 161 | } 162 | addressAssemblableMap.put(addressList.get(0), 163 | SpaceDirective.of(Constants.BYTES_PER_WORD * addressList.size())); 164 | } 165 | } 166 | 167 | public void packStorageDirective() { 168 | packByteStorageDirective(); 169 | packZeroWordStorageDirective(); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/InstructionDisassembler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | import me.zhanghai.mipsasm.assembler.InstructionInformation; 9 | import me.zhanghai.mipsasm.util.BitArray; 10 | 11 | public interface InstructionDisassembler { 12 | void disassemble(InstructionInformation information, BitArray bitArray, DisassemblyContext context); 13 | } 14 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/InstructionWordDisassembler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.InternalException; 10 | import me.zhanghai.mipsasm.assembler.InstructionInformation; 11 | import me.zhanghai.mipsasm.assembler.Operation; 12 | import me.zhanghai.mipsasm.util.BitArray; 13 | 14 | public class InstructionWordDisassembler { 15 | 16 | public static void disassemble(BitArray bitArray, DisassemblyContext context) throws DisassemblerException { 17 | 18 | if (bitArray.length() != Constants.INSTRUCTION_LENGTH) { 19 | throw new InternalException(new IllegalArgumentException( 20 | "BitArray cannot be an instruction by its length, BitArray: " + bitArray)); 21 | } 22 | 23 | BitArray operationCode = bitArray.subArray(26, 32); 24 | BitArray operationSource = bitArray.subArray(21, 26); 25 | BitArray operationSource2 = bitArray.subArray(16, 21); 26 | BitArray operationFunction = bitArray.subArray(0, 6); 27 | Operation operation; 28 | try { 29 | operation = Operation.of(operationCode, operationSource, operationSource2, operationFunction); 30 | } catch (IllegalArgumentException e) { 31 | throw new NoSuchOperationException("Instruction: " + bitArray, e); 32 | } 33 | 34 | InstructionInformation instructionInformation = InstructionInformation.ofOperation(operation); 35 | InstructionDisassembler instructionDisassembler; 36 | try { 37 | instructionDisassembler = instructionInformation.getDisassembler(); 38 | } catch (InternalException e) { 39 | throw new DisassemblerException("Operation has no instruction disassembler: " + operation, e); 40 | } 41 | instructionDisassembler.disassemble(instructionInformation, bitArray, context); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/NoSuchOperationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | public class NoSuchOperationException extends DisassemblerException { 9 | 10 | public NoSuchOperationException() {} 11 | 12 | public NoSuchOperationException(String message) { 13 | super(message); 14 | } 15 | 16 | public NoSuchOperationException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public NoSuchOperationException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/StorageDirectiveDisassembler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.StorageDirective; 10 | import me.zhanghai.mipsasm.util.BitArray; 11 | 12 | public class StorageDirectiveDisassembler { 13 | 14 | // Storage directive must be disassemble to .byte s first so that labels can be at any byte address. 15 | public static void disassemble(BitArray bitArray, DisassemblyContext context) throws DisassemblerException { 16 | switch (bitArray.length()) { 17 | case 4 * Constants.BYTE_LENGTH: 18 | context.appendAssemblable(StorageDirective.of(bitArray.subArray(3 * Constants.BYTE_LENGTH, 19 | 4 * Constants.BYTE_LENGTH)), 1); 20 | // Fall through! 21 | case 3 * Constants.BYTE_LENGTH: 22 | context.appendAssemblable(StorageDirective.of(bitArray.subArray(2 * Constants.BYTE_LENGTH, 23 | 3 * Constants.BYTE_LENGTH)), 1); 24 | // Fall through! 25 | case 2 * Constants.BYTE_LENGTH: 26 | context.appendAssemblable(StorageDirective.of(bitArray.subArray(Constants.BYTE_LENGTH, 27 | 2 * Constants.BYTE_LENGTH)), 1); 28 | // Fall through 29 | case Constants.BYTE_LENGTH: 30 | context.appendAssemblable(StorageDirective.of(bitArray.subArray(0, Constants.BYTE_LENGTH)), 1); 31 | break; 32 | default: 33 | throw new DisassemblerException("Storage directive length is not 1 to 4 bytes: " 34 | + bitArray.length()); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/disassembler/WordDisassembler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.disassembler; 7 | 8 | import me.zhanghai.mipsasm.util.BitArray; 9 | 10 | public class WordDisassembler { 11 | 12 | public static void disassemble(BitArray bitArray, DisassemblyContext context) throws DisassemblerException { 13 | try { 14 | InstructionWordDisassembler.disassemble(bitArray, context); 15 | } catch (DisassemblerException e) { 16 | StorageDirectiveDisassembler.disassemble(bitArray, context); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/gui/AboutDialog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.gui; 7 | 8 | import org.eclipse.swt.SWT; 9 | import org.eclipse.swt.events.SelectionAdapter; 10 | import org.eclipse.swt.events.SelectionEvent; 11 | import org.eclipse.swt.graphics.Image; 12 | import org.eclipse.swt.layout.RowLayout; 13 | import org.eclipse.swt.program.Program; 14 | import org.eclipse.swt.widgets.*; 15 | 16 | import java.util.ResourceBundle; 17 | 18 | public class AboutDialog extends Dialog { 19 | 20 | private static final String WEBSITE_URL = "https://github.com/zhanghai/mipsasm"; 21 | 22 | private static final String LICENSE_URL = "https://www.gnu.org/licenses/gpl.html"; 23 | 24 | private Shell shell; 25 | 26 | private ResourceBundle resourceBundle; 27 | 28 | private Image icon; 29 | 30 | public AboutDialog(Shell shell, ResourceBundle resourceBundle, Image icon) { 31 | super(shell); 32 | this.resourceBundle = resourceBundle; 33 | this.icon = icon; 34 | } 35 | 36 | public AboutDialog(Shell shell, int style, ResourceBundle resourceBundle, Image icon) { 37 | super(shell, style); 38 | this.resourceBundle = resourceBundle; 39 | this.icon = icon; 40 | } 41 | 42 | public void open() { 43 | 44 | onCreateShell(); 45 | 46 | shell.open(); 47 | Display display = getParent().getDisplay(); 48 | while (!shell.isDisposed()) { 49 | if (!display.readAndDispatch()) { 50 | display.sleep(); 51 | } 52 | } 53 | } 54 | 55 | public void onCreateShell() { 56 | 57 | shell = new Shell(getParent()); 58 | 59 | shell.setText(resourceBundle.getString("about.title")); 60 | 61 | RowLayout rowLayout = new RowLayout(); 62 | rowLayout.marginWidth = rowLayout.marginHeight = 12; 63 | rowLayout.center = true; 64 | rowLayout.spacing = 12; 65 | rowLayout.type = SWT.VERTICAL; 66 | shell.setLayout(rowLayout); 67 | 68 | Label iconLabel = new Label(shell, SWT.NONE); 69 | iconLabel.setImage(icon); 70 | 71 | Label nameLabel = new Label(shell, SWT.NONE); 72 | nameLabel.setText(Display.getAppName()); 73 | SwtUtils.setFontStyle(nameLabel, SWT.BOLD); 74 | 75 | Label versionLabel = new Label(shell, SWT.NONE); 76 | versionLabel.setText(Display.getAppVersion()); 77 | 78 | Label descriptionLabel = new Label(shell, SWT.NONE); 79 | descriptionLabel.setText(resourceBundle.getString("about.description")); 80 | 81 | Link websiteLink = new Link(shell, SWT.NONE); 82 | websiteLink.setText("" + resourceBundle.getString("about.website") + ""); 83 | websiteLink.addSelectionListener(new SelectionAdapter() { 84 | @Override 85 | public void widgetSelected(SelectionEvent e) { 86 | Program.launch(WEBSITE_URL); 87 | } 88 | }); 89 | 90 | Label copyrightLabel = new Label(shell, SWT.NONE); 91 | copyrightLabel.setText(resourceBundle.getString("about.copyright")); 92 | SwtUtils.setFontHeight(copyrightLabel, 10); 93 | 94 | Composite licenseComposite = new Composite(shell, SWT.NONE); 95 | RowLayout licenseCompositeLayout = new RowLayout(); 96 | licenseCompositeLayout.center = true; 97 | licenseCompositeLayout.type = SWT.VERTICAL; 98 | licenseComposite.setLayout(licenseCompositeLayout); 99 | Label warrantyLink = new Label(licenseComposite, SWT.NONE); 100 | warrantyLink.setText(resourceBundle.getString("about.warranty")); 101 | SwtUtils.setFontHeight(warrantyLink, 10); 102 | Link licenseLink = new Link(licenseComposite, SWT.NONE); 103 | licenseLink.setText(resourceBundle.getString("about.license")); 104 | licenseLink.addSelectionListener(new SelectionAdapter() { 105 | @Override 106 | public void widgetSelected(SelectionEvent e) { 107 | Program.launch(LICENSE_URL); 108 | } 109 | }); 110 | SwtUtils.setFontHeight(licenseLink, 10); 111 | 112 | shell.pack(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/gui/FontDataBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.gui; 7 | 8 | import org.eclipse.swt.graphics.FontData; 9 | 10 | public class FontDataBuilder { 11 | 12 | private boolean nameSet; 13 | private String name; 14 | private boolean heightSet; 15 | private int height; 16 | private boolean styleSet; 17 | private int style; 18 | private boolean localeSet; 19 | private String locale; 20 | 21 | public FontDataBuilder setName(String name) { 22 | this.name = name; 23 | nameSet = true; 24 | return this; 25 | } 26 | 27 | public FontDataBuilder setHeight(int height) { 28 | this.height = height; 29 | heightSet = true; 30 | return this; 31 | } 32 | 33 | public FontDataBuilder setStyle(int style) { 34 | this.style = style; 35 | styleSet = true; 36 | return this; 37 | } 38 | 39 | public FontDataBuilder setLocale(String locale) { 40 | this.locale = locale; 41 | localeSet = true; 42 | return this; 43 | } 44 | 45 | public FontData build() { 46 | FontData fontData = new FontData(); 47 | if (nameSet) { 48 | fontData.setName(name); 49 | } 50 | if (heightSet) { 51 | fontData.setHeight(height); 52 | } 53 | if (styleSet) { 54 | fontData.setStyle(style); 55 | } 56 | if (localeSet) { 57 | fontData.setLocale(locale); 58 | } 59 | return fontData; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/gui/MenuItemBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.gui; 7 | 8 | import org.eclipse.swt.SWT; 9 | import org.eclipse.swt.events.SelectionListener; 10 | import org.eclipse.swt.widgets.Menu; 11 | import org.eclipse.swt.widgets.MenuItem; 12 | 13 | public class MenuItemBuilder { 14 | 15 | private Menu parentMenu; 16 | private int style; 17 | 18 | private boolean selectionListenerSet; 19 | private SelectionListener selectionListener; 20 | private boolean acceleratorSet; 21 | private int accelerator; 22 | private boolean menuSet; 23 | private Menu menu; 24 | private boolean textSet; 25 | private String text; 26 | 27 | public MenuItemBuilder(Menu parentMenu, int style) { 28 | this.parentMenu = parentMenu; 29 | this.style = style; 30 | } 31 | 32 | public MenuItemBuilder(Menu parentMenu) { 33 | this(parentMenu, SWT.NULL); 34 | } 35 | 36 | public MenuItemBuilder addSelectionListener(SelectionListener selectionListener) { 37 | this.selectionListener = selectionListener; 38 | selectionListenerSet = true; 39 | return this; 40 | } 41 | 42 | public MenuItemBuilder setAccelerator(int accelerator) { 43 | this.accelerator = accelerator; 44 | acceleratorSet = true; 45 | return this; 46 | } 47 | 48 | public MenuItemBuilder setMenu(Menu menu) { 49 | this.menu = menu; 50 | menuSet = true; 51 | return this; 52 | } 53 | 54 | public MenuItemBuilder setText(String text) { 55 | this.text = text; 56 | textSet = true; 57 | return this; 58 | } 59 | 60 | public MenuItem build() { 61 | MenuItem menuItem = new MenuItem(parentMenu, style); 62 | if (selectionListenerSet) { 63 | menuItem.addSelectionListener(selectionListener); 64 | } 65 | if (acceleratorSet) { 66 | menuItem.setAccelerator(accelerator); 67 | } 68 | if (menuSet) { 69 | menuItem.setMenu(menu); 70 | } 71 | if (textSet) { 72 | menuItem.setText(text); 73 | } 74 | return menuItem; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/gui/StyledTextUndoRedoHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.gui; 7 | 8 | import org.eclipse.swt.SWT; 9 | import org.eclipse.swt.custom.ExtendedModifyEvent; 10 | import org.eclipse.swt.custom.ExtendedModifyListener; 11 | import org.eclipse.swt.custom.StyledText; 12 | import org.eclipse.swt.events.KeyEvent; 13 | import org.eclipse.swt.events.KeyListener; 14 | 15 | import java.util.Stack; 16 | 17 | /** 18 | * Adds the Undo-Redo functionality (working Ctrl+Z and Ctrl+Y) to an instance of {@link StyledText}. 19 | * 20 | * @author Petr Bodnar 21 | * @see 22 | * http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/SWTUndoRedo.htm - inspiration for this code, though not 23 | * really functioning - it mainly shows which listeners to use... 24 | * @see 25 | * http://stackoverflow.com/questions/7179464/swt-how-to-recreate-a-default-context-menu-for-text-fields - 26 | * "SWT's StyledText doesn't support Undo-Redo out-of-the-box" 27 | */ 28 | public class StyledTextUndoRedoHelper implements KeyListener, ExtendedModifyListener { 29 | 30 | /** 31 | * Encapsulation of the Undo and Redo stack(s). 32 | */ 33 | private static class UndoRedoStack { 34 | 35 | private Stack undo; 36 | private Stack redo; 37 | 38 | public UndoRedoStack() { 39 | undo = new Stack<>(); 40 | redo = new Stack<>(); 41 | } 42 | 43 | public void pushUndo(T delta) { 44 | undo.add(delta); 45 | } 46 | 47 | public void pushRedo(T delta) { 48 | redo.add(delta); 49 | } 50 | 51 | public T popUndo() { 52 | return undo.pop(); 53 | } 54 | 55 | public T popRedo() { 56 | return redo.pop(); 57 | } 58 | 59 | public void clearUndo() { 60 | undo.clear(); 61 | } 62 | 63 | public void clearRedo() { 64 | redo.clear(); 65 | } 66 | 67 | public void clear() { 68 | clearUndo(); 69 | clearRedo(); 70 | } 71 | 72 | public boolean hasUndo() { 73 | return !undo.isEmpty(); 74 | } 75 | 76 | public boolean hasRedo() { 77 | return !redo.isEmpty(); 78 | } 79 | } 80 | 81 | private StyledText styledText; 82 | 83 | private UndoRedoStack stack; 84 | 85 | private boolean isUndo; 86 | 87 | private boolean isRedo; 88 | 89 | /** 90 | * Creates a new instance of this class. Automatically starts listening to corresponding key and modify events 91 | * coming from the given styledText. 92 | * 93 | * @param styledText the text field to which the Undo-Redo functionality should be added 94 | */ 95 | public StyledTextUndoRedoHelper(StyledText styledText) { 96 | 97 | this.styledText = styledText; 98 | stack = new UndoRedoStack<>(); 99 | 100 | styledText.addExtendedModifyListener(this); 101 | styledText.addKeyListener(this); 102 | } 103 | 104 | /* 105 | * (non-Javadoc) 106 | * 107 | * @see 108 | * org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) 109 | */ 110 | @Override 111 | public void keyPressed(KeyEvent e) { 112 | // Listen to CTRL+Z for Undo, to CTRL+Y or CTRL+SHIFT+Z for Redo 113 | boolean isCtrl = (e.stateMask & SWT.CTRL) > 0; 114 | boolean isAlt = (e.stateMask & SWT.ALT) > 0; 115 | if (isCtrl && !isAlt) { 116 | boolean isShift = (e.stateMask & SWT.SHIFT) > 0; 117 | if (!isShift && e.keyCode == 'z') { 118 | undo(); 119 | } else if (!isShift && e.keyCode == 'y' || isShift 120 | && e.keyCode == 'z') { 121 | redo(); 122 | } 123 | } 124 | } 125 | 126 | /* 127 | * (non-Javadoc) 128 | * 129 | * @see 130 | * org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) 131 | */ 132 | @Override 133 | public void keyReleased(KeyEvent e) {} 134 | 135 | /** 136 | * Creates a corresponding Undo or Redo step from the given event and pushes it to the stack. The Redo stack is, 137 | * logically, emptied if the event comes from a normal user action. 138 | * 139 | * @param event The event 140 | * @see org.eclipse.swt.custom.ExtendedModifyListener#modifyText(org.eclipse.swt.custom.ExtendedModifyEvent) 141 | */ 142 | @Override 143 | public void modifyText(ExtendedModifyEvent event) { 144 | if (isUndo) { 145 | stack.pushRedo(event); 146 | } else { // is Redo or a normal user action 147 | stack.pushUndo(event); 148 | if (!isRedo) { 149 | stack.clearRedo(); 150 | // TODO Switch to treat consecutive characters as one event? 151 | } 152 | } 153 | } 154 | 155 | public boolean canUndo() { 156 | return stack.hasUndo(); 157 | } 158 | 159 | public boolean canRedo() { 160 | return stack.hasRedo(); 161 | } 162 | 163 | /** 164 | * Performs the Undo action. A new corresponding Redo step is automatically pushed to the stack. 165 | */ 166 | public void undo() { 167 | if (canUndo()) { 168 | isUndo = true; 169 | revertEvent(stack.popUndo()); 170 | isUndo = false; 171 | } 172 | } 173 | 174 | /** 175 | * Performs the Redo action. A new corresponding Undo step is automatically pushed to the stack. 176 | */ 177 | public void redo() { 178 | if (canRedo()) { 179 | isRedo = true; 180 | revertEvent(stack.popRedo()); 181 | isRedo = false; 182 | } 183 | } 184 | 185 | public void clear() { 186 | stack.clear(); 187 | } 188 | 189 | /** 190 | * Reverts the given modify event, in the way as the Eclipse text editor does it. 191 | * 192 | * @param event The event 193 | */ 194 | private void revertEvent(ExtendedModifyEvent event) { 195 | // This causes the modifyText() listener method to be called. 196 | styledText.replaceTextRange(event.start, event.length, event.replacedText); 197 | styledText.setSelectionRange(event.start, event.replacedText.length()); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/gui/SwtUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.gui; 7 | 8 | import me.zhanghai.mipsasm.util.IoUtils; 9 | import org.eclipse.swt.SWT; 10 | import org.eclipse.swt.events.DisposeEvent; 11 | import org.eclipse.swt.events.DisposeListener; 12 | import org.eclipse.swt.graphics.Color; 13 | import org.eclipse.swt.graphics.Font; 14 | import org.eclipse.swt.graphics.FontData; 15 | import org.eclipse.swt.graphics.Image; 16 | import org.eclipse.swt.widgets.Control; 17 | import org.eclipse.swt.widgets.Display; 18 | 19 | import java.io.File; 20 | import java.io.IOException; 21 | import java.io.InputStream; 22 | import java.nio.file.Files; 23 | import java.nio.file.StandardCopyOption; 24 | 25 | public class SwtUtils { 26 | 27 | private SwtUtils() {} 28 | 29 | public static boolean isDarkTheme() { 30 | Color widgetBackground = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); 31 | int meanComponent = (widgetBackground.getRed() + widgetBackground.getGreen() + widgetBackground.getBlue()) / 3; 32 | return meanComponent < 0x7F; 33 | } 34 | 35 | public static void loadFont(String resourceName) throws IOException { 36 | File file = File.createTempFile(SwtUtils.class.getPackage().getName() + ".", null); 37 | try (InputStream resourceInputStream = SwtUtils.class.getResourceAsStream(resourceName)) { 38 | Files.copy(resourceInputStream, file.toPath(), StandardCopyOption.REPLACE_EXISTING); 39 | } 40 | file.deleteOnExit(); 41 | Display.getCurrent().loadFont(file.getPath()); 42 | } 43 | 44 | public static Image loadImage(String resourceName) { 45 | InputStream inputStream = SwtUtils.class.getResourceAsStream(resourceName); 46 | Image image = new Image(Display.getCurrent(), inputStream); 47 | IoUtils.close(inputStream); 48 | return image; 49 | } 50 | 51 | public static Image[] loadImageArray(String[] resourceNameArray) { 52 | Image[] imageArray = new Image[resourceNameArray.length]; 53 | for (int i = 0; i < resourceNameArray.length; ++i) { 54 | imageArray[i] = loadImage(resourceNameArray[i]); 55 | } 56 | return imageArray; 57 | } 58 | 59 | public static void setFontHeight(Control control, int height) { 60 | Font oldFont = control.getFont(); 61 | FontData[] fontDataArray = oldFont.getFontData(); 62 | for (FontData fontData : fontDataArray) { 63 | fontData.setHeight(height); 64 | } 65 | final Font newFont = new Font(Display.getCurrent(), fontDataArray); 66 | control.setFont(newFont); 67 | control.addDisposeListener(new DisposeListener() { 68 | @Override 69 | public void widgetDisposed(DisposeEvent disposeEvent) { 70 | newFont.dispose(); 71 | } 72 | }); 73 | } 74 | 75 | public static void setFontStyle(Control control, int style) { 76 | Font oldFont = control.getFont(); 77 | FontData[] fontDataArray = oldFont.getFontData(); 78 | for (FontData fontData : fontDataArray) { 79 | fontData.setStyle(style); 80 | } 81 | final Font newFont = new Font(Display.getCurrent(), fontDataArray); 82 | control.setFont(newFont); 83 | control.addDisposeListener(new DisposeListener() { 84 | @Override 85 | public void widgetDisposed(DisposeEvent disposeEvent) { 86 | newFont.dispose(); 87 | } 88 | }); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/gui/Utf8Control.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.gui; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.InputStreamReader; 11 | import java.net.URL; 12 | import java.net.URLConnection; 13 | import java.nio.charset.StandardCharsets; 14 | import java.security.AccessController; 15 | import java.security.PrivilegedActionException; 16 | import java.security.PrivilegedExceptionAction; 17 | import java.util.Locale; 18 | import java.util.PropertyResourceBundle; 19 | import java.util.ResourceBundle; 20 | 21 | public class Utf8Control extends ResourceBundle.Control { 22 | @Override 23 | public ResourceBundle newBundle(String baseName, Locale locale, String format, final ClassLoader loader, final boolean reload) 24 | throws IllegalAccessException, InstantiationException, IOException { 25 | final String resourceName = toResourceName(toBundleName(baseName, locale), "properties"); 26 | ResourceBundle bundle = null; 27 | InputStream stream; 28 | try { 29 | stream = AccessController.doPrivileged( 30 | new PrivilegedExceptionAction() { 31 | public InputStream run() throws IOException { 32 | InputStream is = null; 33 | if (reload) { 34 | URL url = loader.getResource(resourceName); 35 | if (url != null) { 36 | URLConnection connection = url.openConnection(); 37 | if (connection != null) { 38 | // Disable caches to get fresh data for 39 | // reloading. 40 | connection.setUseCaches(false); 41 | is = connection.getInputStream(); 42 | } 43 | } 44 | } else { 45 | is = loader.getResourceAsStream(resourceName); 46 | } 47 | return is; 48 | } 49 | }); 50 | } catch (PrivilegedActionException e) { 51 | throw (IOException) e.getException(); 52 | } 53 | if (stream != null) { 54 | try { 55 | bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8)); 56 | } finally { 57 | stream.close(); 58 | } 59 | } 60 | return bundle; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/AsciiDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 10 | import me.zhanghai.mipsasm.assembler.StorageDirective; 11 | import me.zhanghai.mipsasm.util.BitArray; 12 | import me.zhanghai.mipsasm.util.RegexUtils; 13 | import me.zhanghai.mipsasm.util.StringUtils; 14 | import me.zhanghai.mipsasm.util.UnsignedCompat; 15 | 16 | import java.nio.charset.StandardCharsets; 17 | import java.util.regex.Matcher; 18 | 19 | public class AsciiDirectiveParser { 20 | 21 | private static final ThreadLocal STRING_MATCHER = RegexUtils.makeThreadLocalMatcher( 22 | "(?0; found: 0"); 30 | } 31 | 32 | Matcher stringMatcher = STRING_MATCHER.get(); 33 | for (String operandString : operandStringList) { 34 | stringMatcher.reset(operandString); 35 | if (!stringMatcher.matches()) { 36 | throw new IllegalOperandException("Operand is not a string in double quotation marks: " 37 | + operandString); 38 | } 39 | String string = stringMatcher.group(1); 40 | string = StringUtils.unescapeMips(string); 41 | for (byte b : string.getBytes(StandardCharsets.US_ASCII)) { 42 | StorageDirective storage; 43 | storage = StorageDirective.of(BitArray.of(UnsignedCompat.unsignedByteToInt(b), Constants.BYTE_LENGTH)); 44 | context.appendAssemblable(storage); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/AsciizDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 10 | import me.zhanghai.mipsasm.assembler.StorageDirective; 11 | import me.zhanghai.mipsasm.util.BitArray; 12 | 13 | public class AsciizDirectiveParser { 14 | 15 | private AsciizDirectiveParser() {} 16 | 17 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 18 | 19 | for (String operandString : operandStringList) { 20 | 21 | AsciiDirectiveParser.parse(new String[]{operandString}, context); 22 | 23 | StorageDirective storage; 24 | storage = StorageDirective.of(BitArray.of(0, Constants.BYTE_LENGTH)); 25 | context.appendAssemblable(storage); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/ByteDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 10 | 11 | public class ByteDirectiveParser { 12 | 13 | private ByteDirectiveParser() {} 14 | 15 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 16 | StorageDirectiveParser.parse(operandStringList, context, Constants.BYTE_LENGTH); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/CoprocessorFunctionParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.CoprocessorFunction; 9 | 10 | import javax.script.ScriptException; 11 | 12 | public class CoprocessorFunctionParser { 13 | 14 | private CoprocessorFunctionParser() {} 15 | 16 | public static CoprocessorFunction parse(String coprocessorFunctionString) throws ParserException { 17 | try { 18 | return CoprocessorFunction.of(JavaScriptParser.parseUnsignedInteger(coprocessorFunctionString)); 19 | } catch (ScriptException | NumberFormatException e) { 20 | throw new IllegalOperandException("Unable to parse coprocessor function: " + coprocessorFunctionString, e); 21 | } catch (IllegalArgumentException e) { 22 | throw new IllegalOperandException("coprocessor function length too long: " + coprocessorFunctionString, e); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/DataDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.assembler.BackwardAddressException; 10 | import me.zhanghai.mipsasm.assembler.DataDirective; 11 | import me.zhanghai.mipsasm.assembler.WordImmediate; 12 | 13 | import javax.script.ScriptException; 14 | import java.util.Arrays; 15 | 16 | public class DataDirectiveParser { 17 | 18 | private DataDirectiveParser() {} 19 | 20 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 21 | 22 | if (operandStringList.length != 1) { 23 | throw new OperandCountMismatchException("Expected: [Address], found: " 24 | + Arrays.toString(operandStringList)); 25 | } 26 | 27 | String addressString = operandStringList[0]; 28 | WordImmediate address; 29 | try { 30 | address = WordImmediate.of(JavaScriptParser.parseUnsignedInteger(addressString)); 31 | } catch (ScriptException | IllegalArgumentException e) { 32 | throw new IllegalOperandException("Address: " + addressString, e); 33 | } 34 | if (address.getValue().get(0) || address.getValue().get(1)) { 35 | throw new IllegalOperandException("Address is not word aligned: " + addressString); 36 | } 37 | try { 38 | context.appendAssemblable(DataDirective.of(address)); 39 | } catch (BackwardAddressException e) { 40 | throw new IllegalOperandException("Address moves backward", e); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/DirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.assembler.DirectiveInformation; 10 | import me.zhanghai.mipsasm.util.RegexUtils; 11 | 12 | import java.util.regex.Matcher; 13 | 14 | public class DirectiveParser { 15 | 16 | private static final ThreadLocal MATCHER = RegexUtils.makeThreadLocalMatcher("(\\S+)(?:\\s+(.*))?"); 17 | 18 | private DirectiveParser() {} 19 | 20 | public static void parse(String directiveString, AssemblyContext context) throws ParserException { 21 | 22 | Matcher matcher = MATCHER.get().reset(directiveString); 23 | if (!matcher.matches()) { 24 | throw new IllegalInstructionException("Instruction: " + directiveString); 25 | } 26 | 27 | String directiveName = matcher.group(1); 28 | DirectiveInformation directiveInformation; 29 | try { 30 | directiveInformation = DirectiveInformation.valueOf(directiveName.toUpperCase()); 31 | } catch (IllegalArgumentException e) { 32 | throw new NoSuchDirectiveException("Directive: " + directiveName); 33 | } 34 | 35 | String operandListString = matcher.group(2); 36 | String[] operandStringList = ParserSplitUtils.splitOperands(operandListString); 37 | directiveInformation.parse(operandStringList, context); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/EchoDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | 10 | import javax.script.ScriptException; 11 | 12 | public class EchoDirectiveParser { 13 | 14 | private EchoDirectiveParser() {} 15 | 16 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 17 | 18 | if (operandStringList.length == 0) { 19 | throw new OperandCountMismatchException("Expected: >0; found: 0"); 20 | } 21 | 22 | for (String operandString : operandStringList) { 23 | String line; 24 | try { 25 | line = JavaScriptParser.eval(operandString).toString(); 26 | } catch (ScriptException e) { 27 | throw new ParserException("Error evaluating JavaScript", e); 28 | } 29 | try { 30 | LineParser.parse(line, context); 31 | } catch (ParserException e) { 32 | throw new ParserException("Error assembling echoed line: " + line, e); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/EvalDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | 10 | import javax.script.ScriptException; 11 | 12 | public class EvalDirectiveParser { 13 | 14 | private EvalDirectiveParser() {} 15 | 16 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 17 | 18 | if (operandStringList.length == 0) { 19 | throw new OperandCountMismatchException("Expected: >0; found: 0"); 20 | } 21 | 22 | for (String operandString : operandStringList) { 23 | try { 24 | JavaScriptParser.eval(operandString); 25 | } catch (ScriptException e) { 26 | throw new ParserException("Error evaluating JavaScript", e); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/HalfWordDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 10 | 11 | public class HalfWordDirectiveParser { 12 | 13 | private HalfWordDirectiveParser() {} 14 | 15 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 16 | StorageDirectiveParser.parse(operandStringList, context, Constants.HALF_WORD_LENGTH); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/IllegalDirectiveException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class IllegalDirectiveException extends ParserException { 9 | 10 | public IllegalDirectiveException() {} 11 | 12 | public IllegalDirectiveException(String message) { 13 | super(message); 14 | } 15 | 16 | public IllegalDirectiveException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public IllegalDirectiveException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/IllegalInstructionException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class IllegalInstructionException extends ParserException { 9 | 10 | public IllegalInstructionException() {} 11 | 12 | public IllegalInstructionException(String message) { 13 | super(message); 14 | } 15 | 16 | public IllegalInstructionException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public IllegalInstructionException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/IllegalLabelException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class IllegalLabelException extends ParserException { 9 | 10 | public IllegalLabelException() {} 11 | 12 | public IllegalLabelException(String message) { 13 | super(message); 14 | } 15 | 16 | public IllegalLabelException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public IllegalLabelException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/IllegalOperandException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class IllegalOperandException extends ParserException { 9 | 10 | public IllegalOperandException() {} 11 | 12 | public IllegalOperandException(String message) { 13 | super(message); 14 | } 15 | 16 | public IllegalOperandException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public IllegalOperandException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/IllegalStatementException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class IllegalStatementException extends ParserException { 9 | 10 | public IllegalStatementException() {} 11 | 12 | public IllegalStatementException(String message) { 13 | super(message); 14 | } 15 | 16 | public IllegalStatementException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public IllegalStatementException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/ImmediateParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.Immediate; 9 | 10 | import javax.script.ScriptException; 11 | 12 | public class ImmediateParser { 13 | 14 | private ImmediateParser() {} 15 | 16 | public static Immediate parse(String immediateString) throws ParserException { 17 | try { 18 | return Immediate.of(JavaScriptParser.parseInteger(immediateString)); 19 | } catch (ScriptException | NumberFormatException e) { 20 | throw new IllegalOperandException("Unable to parse immediate: " + immediateString, e); 21 | } catch (IllegalArgumentException e) { 22 | throw new IllegalOperandException("Immediate length too long: " + immediateString, e); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/InstructionParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.*; 9 | import me.zhanghai.mipsasm.util.RegexUtils; 10 | 11 | import java.util.regex.Matcher; 12 | 13 | public class InstructionParser { 14 | 15 | private static final ThreadLocal MATCHER = RegexUtils.makeThreadLocalMatcher("(\\S+)(?:\\s+(.*))?"); 16 | 17 | private InstructionParser() {} 18 | 19 | public static void parse(String instructionString, AssemblyContext context) throws ParserException { 20 | 21 | Matcher matcher = MATCHER.get().reset(instructionString); 22 | if (!matcher.matches()) { 23 | throw new IllegalInstructionException(instructionString); 24 | } 25 | 26 | String operationName = matcher.group(1); 27 | Operation operation; 28 | try { 29 | operation = Operation.valueOf(operationName.toUpperCase()); 30 | } catch (IllegalArgumentException e) { 31 | throw new NoSuchOperationException(operationName); 32 | } 33 | 34 | String operandListString = matcher.group(2); 35 | String[] operandStringList = ParserSplitUtils.splitOperands(operandListString); 36 | OperandInstance[] operandInstances = OperandListParser.parse(operandStringList, 37 | InstructionInformation.ofOperation(operation).getOperandListPrototype()); 38 | 39 | context.appendAssemblable(Instruction.of(operation, operandInstances)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/JavaScriptParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.util.IoUtils; 9 | 10 | import javax.script.ScriptEngine; 11 | import javax.script.ScriptEngineManager; 12 | import javax.script.ScriptException; 13 | 14 | public class JavaScriptParser { 15 | 16 | private static final ScriptEngine JAVA_SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("JavaScript"); 17 | 18 | private JavaScriptParser() {} 19 | 20 | public static Object eval(String script) throws ScriptException { 21 | return JAVA_SCRIPT_ENGINE.eval(script); 22 | } 23 | 24 | private static String evalForInteger(String script) throws ScriptException { 25 | Object result = eval(script); 26 | // Double is default return type for Number. 27 | if (result instanceof Double && result.equals(Math.rint((Double) result))) { 28 | // Java's signed int will make 0x7FFFFFFF for values larger than that if we use Double.intValue(). 29 | result = ((Double) result).longValue(); 30 | } 31 | return result.toString(); 32 | } 33 | 34 | public static int parseSignedInteger(String expression) throws ScriptException { 35 | try { 36 | return IoUtils.parseSignedInteger(expression); 37 | } catch (NumberFormatException e) { 38 | expression = evalForInteger(expression); 39 | return IoUtils.parseSignedInteger(expression); 40 | } 41 | } 42 | 43 | public static int parseUnsignedInteger(String expression) throws ScriptException { 44 | try { 45 | return IoUtils.parseUnsignedInteger(expression); 46 | } catch (NumberFormatException e) { 47 | expression = evalForInteger(expression); 48 | return IoUtils.parseUnsignedInteger(expression); 49 | } 50 | } 51 | 52 | public static int parseInteger(String expression) throws ScriptException { 53 | try { 54 | return IoUtils.parseInteger(expression); 55 | } catch (NumberFormatException e) { 56 | expression = evalForInteger(expression); 57 | return IoUtils.parseInteger(expression); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/LabelAlreadyDefinedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class LabelAlreadyDefinedException extends ParserException { 9 | 10 | public LabelAlreadyDefinedException() {} 11 | 12 | public LabelAlreadyDefinedException(String message) { 13 | super(message); 14 | } 15 | 16 | public LabelAlreadyDefinedException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public LabelAlreadyDefinedException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/LabelOperandParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.Label; 9 | 10 | public class LabelOperandParser { 11 | 12 | private LabelOperandParser() {} 13 | 14 | public static Label parse(String labelString) throws ParserException { 15 | try { 16 | return Label.of(labelString); 17 | } catch (IllegalArgumentException e) { 18 | throw new IllegalLabelException("Label name: " + labelString, e); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/LabelParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.util.RegexUtils; 10 | 11 | import java.util.regex.Matcher; 12 | 13 | public class LabelParser { 14 | 15 | private static final ThreadLocal MATCHER = RegexUtils.makeThreadLocalMatcher(Tokens.IDENTIFIER_REGEX); 16 | 17 | private LabelParser() {} 18 | 19 | public static void parse(String labelString, AssemblyContext context) throws ParserException { 20 | 21 | Matcher matcher = MATCHER.get().reset(labelString); 22 | if (!matcher.matches()) { 23 | throw new IllegalLabelException("Label: " + labelString); 24 | } 25 | 26 | context.setPendingLabel(labelString); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/LineParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.util.RegexUtils; 10 | 11 | import java.util.regex.Matcher; 12 | 13 | public class LineParser { 14 | 15 | private static final ThreadLocal COMMENT_MATCHER = RegexUtils.makeThreadLocalMatcher(Tokens.COMMENT_REGEX); 16 | 17 | private LineParser() {} 18 | 19 | public static void parse(String line, AssemblyContext context) throws ParserException { 20 | 21 | line = COMMENT_MATCHER.get().reset(line).replaceAll(""); 22 | 23 | for (String statementString : ParserSplitUtils.splitStatements(line)) { 24 | statementString = statementString.trim(); 25 | if (statementString.isEmpty()) { 26 | continue; 27 | } 28 | StatementParser.parse(statementString, context); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/MigratorException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class MigratorException extends Exception { 9 | 10 | public MigratorException() {} 11 | 12 | public MigratorException(String message) { 13 | super(message); 14 | } 15 | 16 | public MigratorException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public MigratorException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/MultiplePendingLabelException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class MultiplePendingLabelException extends ParserException { 9 | 10 | public MultiplePendingLabelException() {} 11 | 12 | public MultiplePendingLabelException(String message) { 13 | super(message); 14 | } 15 | 16 | public MultiplePendingLabelException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public MultiplePendingLabelException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/NoSuchDirectiveException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class NoSuchDirectiveException extends ParserException { 9 | 10 | public NoSuchDirectiveException() {} 11 | 12 | public NoSuchDirectiveException(String message) { 13 | super(message); 14 | } 15 | 16 | public NoSuchDirectiveException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public NoSuchDirectiveException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/NoSuchOperationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class NoSuchOperationException extends ParserException { 9 | 10 | public NoSuchOperationException() {} 11 | 12 | public NoSuchOperationException(String message) { 13 | super(message); 14 | } 15 | 16 | public NoSuchOperationException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public NoSuchOperationException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/OffsetBaseParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.Immediate; 9 | import me.zhanghai.mipsasm.assembler.OffsetBase; 10 | import me.zhanghai.mipsasm.assembler.Register; 11 | import me.zhanghai.mipsasm.util.RegexUtils; 12 | 13 | import javax.script.ScriptException; 14 | import java.util.regex.Matcher; 15 | 16 | public class OffsetBaseParser { 17 | 18 | private static final ThreadLocal MATCHER = 19 | RegexUtils.makeThreadLocalMatcher("(\\S*)\\s*\\(\\s*(\\S+)\\s*\\)"); 20 | 21 | private OffsetBaseParser() {} 22 | 23 | public static OffsetBase parse(String offsetBaseString) throws ParserException { 24 | 25 | Matcher offsetBaseMatcher = MATCHER.get().reset(offsetBaseString); 26 | 27 | if (!offsetBaseMatcher.matches()) { 28 | throw new IllegalOperandException("Cannot parse offset and base: " + offsetBaseString); 29 | } 30 | 31 | Immediate offset; 32 | String offsetString = offsetBaseMatcher.group(1); 33 | if (offsetString.isEmpty()) { 34 | offset = Immediate.of(0); 35 | } else { 36 | try { 37 | offset = Immediate.of(JavaScriptParser.parseSignedInteger(offsetString)); 38 | } catch (ScriptException | NumberFormatException e) { 39 | throw new IllegalOperandException("Offset cannot be parsed: " + offsetString, e); 40 | } catch (IllegalArgumentException e) { 41 | throw new IllegalOperandException("Offset length to long: " + offsetString, e); 42 | } 43 | } 44 | 45 | Register base; 46 | String baseString = offsetBaseMatcher.group(2); 47 | base = RegisterParser.parse(baseString); 48 | 49 | return OffsetBase.of(base, offset); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/OffsetParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.Immediate; 9 | import me.zhanghai.mipsasm.assembler.Offset; 10 | import me.zhanghai.mipsasm.assembler.OffsetLabel; 11 | 12 | import javax.script.ScriptException; 13 | 14 | public class OffsetParser { 15 | 16 | private OffsetParser() {} 17 | 18 | public static Offset parse(String offsetString) throws ParserException { 19 | try { 20 | return Offset.of(Immediate.of(JavaScriptParser.parseSignedInteger(offsetString))); 21 | } catch (ScriptException | NumberFormatException e) { 22 | try { 23 | return Offset.of(OffsetLabel.of(offsetString)); 24 | } catch (IllegalArgumentException ex) { 25 | throw new IllegalLabelException("Offset label name: " + offsetString, ex); 26 | } 27 | } catch (IllegalArgumentException e) { 28 | throw new IllegalOperandException("Offset value length too long", e); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/OperandCountMismatchException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class OperandCountMismatchException extends ParserException { 9 | 10 | public OperandCountMismatchException() {} 11 | 12 | public OperandCountMismatchException(String message) { 13 | super(message); 14 | } 15 | 16 | public OperandCountMismatchException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public OperandCountMismatchException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/OperandListParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.Operand; 9 | import me.zhanghai.mipsasm.assembler.OperandInstance; 10 | import me.zhanghai.mipsasm.assembler.OperandPrototype; 11 | 12 | import java.util.Arrays; 13 | 14 | public class OperandListParser { 15 | 16 | private OperandListParser() {} 17 | 18 | public static OperandInstance[] parse(String[] operandStringList, OperandPrototype[] operandListPrototype) 19 | throws ParserException { 20 | 21 | if (operandStringList.length != operandListPrototype.length) { 22 | throw new OperandCountMismatchException("Expected: " + Arrays.toString(operandListPrototype) + ", found: " 23 | + Arrays.toString(operandStringList)); 24 | } 25 | 26 | int operandCount = operandListPrototype.length; 27 | OperandInstance[] operandListInstance = new OperandInstance[operandCount]; 28 | for (int i = 0; i < operandCount; ++i) { 29 | OperandPrototype operandPrototype = operandListPrototype[i]; 30 | String operandString = operandStringList[i]; 31 | Operand operand; 32 | switch (operandPrototype.getType()) { 33 | case REGISTER: 34 | operand = RegisterParser.parse(operandString); 35 | break; 36 | case IMMEDIATE: 37 | operand = ImmediateParser.parse(operandString); 38 | break; 39 | case OFFSET: 40 | operand = OffsetParser.parse(operandString); 41 | break; 42 | case COPROCESSOR_FUNCTION: 43 | operand = CoprocessorFunctionParser.parse(operandString); 44 | break; 45 | case SHIFT_AMOUNT: 46 | operand = ShiftAmountParser.parse(operandString); 47 | break; 48 | case TARGET: 49 | operand = TargetParser.parse(operandString); 50 | break; 51 | case OFFSET_BASE: 52 | operand = OffsetBaseParser.parse(operandString); 53 | break; 54 | case WORD_IMMEDIATE: 55 | operand = WordImmediateParser.parse(operandString); 56 | break; 57 | case LABEL: 58 | operand = LabelOperandParser.parse(operandString); 59 | break; 60 | default: 61 | // Never happens. 62 | throw new RuntimeException("Unknown operand type: " + operandPrototype.getType()); 63 | } 64 | operandListInstance[i] = OperandInstance.fromPrototype(operandPrototype, operand); 65 | } 66 | 67 | return operandListInstance; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/Parser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | import java.nio.charset.StandardCharsets; 15 | 16 | public class Parser { 17 | 18 | private static final String CONTINUATION_STRING = "\\"; 19 | 20 | private Parser() {} 21 | 22 | public static void parse(InputStream inputStream, AssemblyContext context) throws ParserException { 23 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); 24 | int lineNumber = 0; 25 | String line = ""; 26 | boolean hasContinuation = false; 27 | while (true) { 28 | ++lineNumber; 29 | try { 30 | if (hasContinuation) { 31 | line += reader.readLine(); 32 | } else { 33 | line = reader.readLine(); 34 | } 35 | } catch (IOException e) { 36 | throw new ParserException("Line " + lineNumber, e); 37 | } 38 | if (line == null) { 39 | break; 40 | } 41 | hasContinuation = line.endsWith(CONTINUATION_STRING); 42 | if (hasContinuation) { 43 | line = line.substring(0, line.length() - CONTINUATION_STRING.length()); 44 | } else { 45 | try { 46 | LineParser.parse(line, context); 47 | } catch (ParserException e) { 48 | throw new ParserException("Line " + lineNumber + ": " + line, e); 49 | } 50 | } 51 | } 52 | context.finishAllocation(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/ParserException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class ParserException extends Exception { 9 | 10 | public ParserException() {} 11 | 12 | public ParserException(String message) { 13 | super(message); 14 | } 15 | 16 | public ParserException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public ParserException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/ParserSplitUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.util.StringUtils; 9 | 10 | import java.util.regex.Matcher; 11 | 12 | public class ParserSplitUtils { 13 | 14 | private static final String SPLIT_DEFAULT_STATEMENT_REGEX = "\\s*" + Tokens.STATEMENT_SEPARATOR_REGEX + "\\s*"; 15 | private static final String SPLIT_DEFAULT_OPERAND_REGEX = "\\s*" + Tokens.OPERAND_SEPARATOR_REGEX + "\\s*"; 16 | private static final String[] SPLIT_DEFAULT_QUOTES_REGEX = new String[] {"\"", "'"}; 17 | private static final String[] SPLIT_DEFAULT_LEFT_BRACKET_REGEX = new String[] {"\\(", "\\[", "\\{"}; 18 | private static final String[] SPLIT_DEFAULT_RIGHT_BRACKET_REGEX = new String[] {"\\)", "\\]", "\\}"}; 19 | private static final ThreadLocal SPLIT_DEFAULT_STATEMENT_DELIMITER_MATCHER = new ThreadLocal() { 20 | @Override 21 | protected Matcher initialValue() { 22 | return StringUtils.prepareMatcherForSplit(SPLIT_DEFAULT_STATEMENT_REGEX, SPLIT_DEFAULT_QUOTES_REGEX, 23 | SPLIT_DEFAULT_LEFT_BRACKET_REGEX, SPLIT_DEFAULT_RIGHT_BRACKET_REGEX); 24 | } 25 | }; 26 | private static final ThreadLocal SPLIT_DEFAULT_OPERAND_DELIMITER_MATCHER = new ThreadLocal() { 27 | @Override 28 | protected Matcher initialValue() { 29 | return StringUtils.prepareMatcherForSplit(SPLIT_DEFAULT_OPERAND_REGEX, SPLIT_DEFAULT_QUOTES_REGEX, 30 | SPLIT_DEFAULT_LEFT_BRACKET_REGEX, SPLIT_DEFAULT_RIGHT_BRACKET_REGEX); 31 | } 32 | }; 33 | 34 | public static final String[] EMPTY_ARRAY = new String[] {}; 35 | 36 | private ParserSplitUtils() {} 37 | 38 | private static String[] trimEmptyArray(String[] array) { 39 | if (array.length == 1 && array[0].isEmpty()) { 40 | return EMPTY_ARRAY; 41 | } else { 42 | return array; 43 | } 44 | } 45 | 46 | public static String[] splitStatements(String string) { 47 | if (string == null) { 48 | return EMPTY_ARRAY; 49 | } 50 | return trimEmptyArray(StringUtils.split(string, SPLIT_DEFAULT_STATEMENT_REGEX, SPLIT_DEFAULT_QUOTES_REGEX, 51 | SPLIT_DEFAULT_LEFT_BRACKET_REGEX, SPLIT_DEFAULT_RIGHT_BRACKET_REGEX, 52 | SPLIT_DEFAULT_STATEMENT_DELIMITER_MATCHER.get())); 53 | } 54 | 55 | public static String[] splitOperands(String string) { 56 | if (string == null) { 57 | return EMPTY_ARRAY; 58 | } 59 | return trimEmptyArray(StringUtils.split(string, SPLIT_DEFAULT_OPERAND_REGEX, SPLIT_DEFAULT_QUOTES_REGEX, 60 | SPLIT_DEFAULT_LEFT_BRACKET_REGEX, SPLIT_DEFAULT_RIGHT_BRACKET_REGEX, 61 | SPLIT_DEFAULT_OPERAND_DELIMITER_MATCHER.get())); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/PendingLabelException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class PendingLabelException extends ParserException { 9 | 10 | public PendingLabelException() {} 11 | 12 | public PendingLabelException(String message) { 13 | super(message); 14 | } 15 | 16 | public PendingLabelException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public PendingLabelException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/RegisterParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.Register; 9 | import me.zhanghai.mipsasm.util.RegexUtils; 10 | 11 | import java.util.regex.Matcher; 12 | 13 | public class RegisterParser { 14 | 15 | private static final ThreadLocal MATCHER = RegexUtils.makeThreadLocalMatcher("\\$(\\S+)"); 16 | 17 | private RegisterParser() {} 18 | 19 | public static Register parse(String registerString) throws ParserException { 20 | 21 | Matcher matcher = MATCHER.get().reset(registerString); 22 | if (!matcher.matches()) { 23 | throw new IllegalOperandException("Cannot parse register: " + registerString); 24 | } 25 | 26 | String registerName = matcher.group(1); 27 | try { 28 | return Register.values()[Integer.parseInt(registerName)]; 29 | } catch (IndexOutOfBoundsException e) { 30 | throw new IllegalOperandException("Register index out of bounds: " + registerName, e); 31 | } catch (NumberFormatException ignored) { 32 | try { 33 | return Register.valueOf(registerName.toUpperCase()); 34 | } catch (IllegalArgumentException e) { 35 | throw new IllegalOperandException("Invalid register name: " + registerName, e); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/ShiftAmountParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.ShiftAmount; 9 | 10 | import javax.script.ScriptException; 11 | 12 | public class ShiftAmountParser { 13 | 14 | private ShiftAmountParser() {} 15 | 16 | public static ShiftAmount parse(String shiftAmountString) throws ParserException { 17 | try { 18 | return ShiftAmount.of(JavaScriptParser.parseUnsignedInteger(shiftAmountString)); 19 | } catch (ScriptException | NumberFormatException e) { 20 | throw new IllegalOperandException("Unable to parse shift amount: " + shiftAmountString, e); 21 | } catch (IllegalArgumentException e) { 22 | throw new IllegalOperandException("Shift amount length too long: " + shiftAmountString, e); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/SpaceDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.assembler.SpaceDirective; 10 | 11 | import javax.script.ScriptException; 12 | import java.util.Arrays; 13 | 14 | public class SpaceDirectiveParser { 15 | 16 | private SpaceDirectiveParser() {} 17 | 18 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 19 | 20 | if (operandStringList.length != 1) { 21 | throw new OperandCountMismatchException("Expected: [ByteCount], found: " 22 | + Arrays.toString(operandStringList)); 23 | } 24 | 25 | String byteCountString = operandStringList[0]; 26 | SpaceDirective space; 27 | try { 28 | space = SpaceDirective.of(JavaScriptParser.parseUnsignedInteger(byteCountString)); 29 | } catch (ScriptException | IllegalArgumentException e) { 30 | throw new IllegalOperandException("ByteCount: " + byteCountString, e); 31 | } 32 | context.appendAssemblable(space); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/SqsMigrator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.util.IoUtils; 9 | import me.zhanghai.mipsasm.util.RegexUtils; 10 | 11 | import java.util.regex.Matcher; 12 | import java.util.regex.Pattern; 13 | 14 | public class SqsMigrator { 15 | 16 | // RegexMigrator is case insensitive. 17 | private static final Migrator[] MIGRATORS = new Migrator[] { 18 | new RegexMigrator("#baseAddr", ".text"), 19 | new ColonedDirectiveMigrator("#DataAddre", "data"), 20 | new RegexMigrator("\\bdb\\b", ".byte"), 21 | new RegexMigrator("\\bdw\\b", ".half"), 22 | new RegexMigrator("\\bdd\\b", ".word"), 23 | new RegexMigrator("\\bresb\\b", ".space"), 24 | new RegexMigrator("\\bRESW\\b", ".space 2 *"), 25 | new RegexMigrator("\\bRESD\\b", ".space 4 *"), 26 | new MultiplicationMigrator(), 27 | new RegexMigrator("(? matcher; 54 | private String replacement; 55 | 56 | public RegexMigrator(String regex, String replacement) { 57 | this.matcher = RegexUtils.makeThreadLocalMatcher(regex, Pattern.CASE_INSENSITIVE); 58 | this.replacement = replacement; 59 | } 60 | 61 | @Override 62 | public String migrate(String text) { 63 | return matcher.get().reset(text).replaceAll(replacement); 64 | } 65 | } 66 | 67 | private static class ColonedDirectiveMigrator implements Migrator { 68 | 69 | private RegexMigrator migrator1, migrator2; 70 | 71 | protected ColonedDirectiveMigrator(RegexMigrator migrator1, RegexMigrator migrator2) { 72 | this.migrator1 = migrator1; 73 | this.migrator2 = migrator2; 74 | } 75 | 76 | public ColonedDirectiveMigrator(String colonedDirective, String directive) { 77 | migrator1 = new RegexMigrator(colonedDirective + ":(?=\\S)", "." + directive + " "); 78 | migrator2 = new RegexMigrator(colonedDirective + ":", "." + directive); 79 | } 80 | 81 | @Override 82 | public String migrate(String text) throws MigratorException { 83 | text = migrator1.migrate(text); 84 | return migrator2.migrate(text); 85 | } 86 | } 87 | 88 | private static class MultiplyingColonedDirectiveMigrator extends ColonedDirectiveMigrator { 89 | 90 | public MultiplyingColonedDirectiveMigrator(String colonedDirective, String directive, int multiplier) { 91 | super(new RegexMigrator(colonedDirective + ":(\\s+)", "." + directive + "$1" + multiplier + " * "), 92 | new RegexMigrator(colonedDirective + ":", "." + directive + multiplier + " * ")); 93 | } 94 | } 95 | 96 | private static class MultiplicationMigrator implements Migrator { 97 | @Override 98 | public String migrate(String text) throws MigratorException { 99 | // HACK: For ignoring comment. 100 | Matcher matcher = Pattern.compile("(? 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.util.RegexUtils; 10 | 11 | import java.util.regex.Matcher; 12 | 13 | public class StatementParser { 14 | 15 | private static final String GROUP_LABEL = "label"; 16 | private static final String GROUP_DIRECTIVE_OR_INSTRUCTION = "directiveOrInstruction"; 17 | private static final ThreadLocal MATCHER = RegexUtils.makeThreadLocalMatcher( 18 | "(?:(?<" + GROUP_LABEL + ">\\S+):)?\\s*(?<" + GROUP_DIRECTIVE_OR_INSTRUCTION + ">.+)?"); 19 | 20 | private static final String DIRECTIVE_PREFIX = "."; 21 | 22 | private StatementParser() {} 23 | 24 | public static void parse(String statement, AssemblyContext context) throws ParserException { 25 | 26 | Matcher matcher = MATCHER.get().reset(statement); 27 | 28 | if (!matcher.matches()) { 29 | throw new IllegalStatementException("Statement: " + statement); 30 | } 31 | 32 | String labelString = matcher.group(GROUP_LABEL); 33 | if (labelString != null) { 34 | LabelParser.parse(labelString, context); 35 | } 36 | 37 | String directiveOrInstructionString = matcher.group(GROUP_DIRECTIVE_OR_INSTRUCTION); 38 | if (directiveOrInstructionString != null) { 39 | if (directiveOrInstructionString.startsWith(DIRECTIVE_PREFIX)) { 40 | String directiveString = directiveOrInstructionString.substring(DIRECTIVE_PREFIX.length()); 41 | DirectiveParser.parse(directiveString, context); 42 | } else { 43 | String instructionString = directiveOrInstructionString; 44 | InstructionParser.parse(instructionString, context); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/StorageDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.assembler.StorageDirective; 10 | 11 | import javax.script.ScriptException; 12 | 13 | public abstract class StorageDirectiveParser { 14 | 15 | private StorageDirectiveParser() {} 16 | 17 | static void parse(String[] operandStringList, AssemblyContext context, int length) throws ParserException { 18 | 19 | if (operandStringList.length == 0) { 20 | throw new OperandCountMismatchException("Expected: >0; found: 0"); 21 | } 22 | 23 | for (String operandString : operandStringList) { 24 | StorageDirective storage; 25 | try { 26 | storage = StorageDirective.of(JavaScriptParser.parseUnsignedInteger(operandString), length); 27 | } catch (ScriptException | IllegalArgumentException e) { 28 | throw new IllegalOperandException("Operand: " + operandString, e); 29 | } 30 | context.appendAssemblable(storage); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/TargetLabelParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.TargetLabel; 9 | 10 | public class TargetLabelParser { 11 | 12 | private TargetLabelParser() {} 13 | 14 | public static TargetLabel parse(String labelString) throws ParserException { 15 | try { 16 | return TargetLabel.of(labelString); 17 | } catch (IllegalArgumentException e) { 18 | throw new IllegalOperandException("Illegal label name: " + labelString, e); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/TargetParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.InstructionIndex; 9 | import me.zhanghai.mipsasm.assembler.Target; 10 | import me.zhanghai.mipsasm.assembler.TargetLabel; 11 | 12 | import javax.script.ScriptException; 13 | 14 | public class TargetParser { 15 | 16 | private TargetParser() {} 17 | 18 | public static Target parse(String targetString) throws ParserException { 19 | try { 20 | return Target.of(InstructionIndex.of(JavaScriptParser.parseUnsignedInteger(targetString))); 21 | } catch (ScriptException | NumberFormatException e) { 22 | try { 23 | return Target.of(TargetLabel.of(targetString)); 24 | } catch (IllegalArgumentException ex) { 25 | throw new IllegalLabelException("Target label name: " + targetString, ex); 26 | } 27 | } catch (IllegalArgumentException e) { 28 | throw new IllegalOperandException("Target value length too long", e); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/TextDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.assembler.BackwardAddressException; 10 | import me.zhanghai.mipsasm.assembler.TextDirective; 11 | import me.zhanghai.mipsasm.assembler.WordImmediate; 12 | 13 | import javax.script.ScriptException; 14 | import java.util.Arrays; 15 | 16 | public class TextDirectiveParser { 17 | 18 | private TextDirectiveParser() {} 19 | 20 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 21 | 22 | if (operandStringList.length != 1) { 23 | throw new OperandCountMismatchException("Expected: [Address], found: " 24 | + Arrays.toString(operandStringList)); 25 | } 26 | 27 | String addressString = operandStringList[0]; 28 | WordImmediate address; 29 | try { 30 | address = WordImmediate.of(JavaScriptParser.parseUnsignedInteger(addressString)); 31 | } catch (ScriptException | IllegalArgumentException e) { 32 | throw new IllegalOperandException("Address: " + addressString, e); 33 | } 34 | if (address.getValue().get(0) || address.getValue().get(1)) { 35 | throw new IllegalOperandException("Address is not word aligned: " + addressString); 36 | } 37 | try { 38 | context.appendAssemblable(TextDirective.of(address)); 39 | } catch (BackwardAddressException e) { 40 | throw new IllegalOperandException("Address moves backward", e); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/Tokens.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | public class Tokens { 9 | 10 | private Tokens() {} 11 | 12 | public static final String COMMENT_REGEX = "(?:#.*)|(?://.*)|(?:/\\*.*?\\*/)"; 13 | 14 | public static final String IDENTIFIER_REGEX = "[a-zA-Z._$][0-9a-zA-Z._$]*"; 15 | 16 | public static final String STATEMENT_SEPARATOR_REGEX = ";"; 17 | 18 | public static final String OPERAND_SEPARATOR_REGEX = ","; 19 | 20 | public static final String STRING_QUOTATION = "\""; 21 | } 22 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/WordDirectiveParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 10 | 11 | public class WordDirectiveParser { 12 | 13 | private WordDirectiveParser() {} 14 | 15 | public static void parse(String[] operandStringList, AssemblyContext context) throws ParserException { 16 | StorageDirectiveParser.parse(operandStringList, context, Constants.WORD_LENGTH); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/parser/WordImmediateParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.parser; 7 | 8 | import me.zhanghai.mipsasm.assembler.WordImmediate; 9 | 10 | import javax.script.ScriptException; 11 | 12 | public class WordImmediateParser { 13 | 14 | private WordImmediateParser() {} 15 | 16 | public static WordImmediate parse(String wordImmediateString) throws ParserException { 17 | try { 18 | return WordImmediate.of(JavaScriptParser.parseInteger(wordImmediateString)); 19 | } catch (ScriptException | NumberFormatException e) { 20 | throw new IllegalOperandException("Unable to parse word immediate: " + wordImmediateString, e); 21 | } catch (IllegalArgumentException e) { 22 | throw new IllegalOperandException("Word immediate length too long: " + wordImmediateString, e); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/util/HexUnescaper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.util; 7 | 8 | import org.apache.commons.lang3.text.translate.CharSequenceTranslator; 9 | 10 | import java.io.IOException; 11 | import java.io.Writer; 12 | 13 | public class HexUnescaper extends CharSequenceTranslator { 14 | 15 | @Override 16 | public int translate(final CharSequence input, final int index, final Writer out) throws IOException { 17 | 18 | int remaining = input.length() - index - 1; // how many characters left, ignoring the leading \ 19 | StringBuilder builder = new StringBuilder(); 20 | 21 | if(input.charAt(index) == '\\' && remaining > 0 && isX(input.charAt(index + 1))) { 22 | 23 | int next2 = index + 2; 24 | int next3 = index + 3; 25 | 26 | if (remaining > 1 && isHexDigit(input.charAt(next2))) { 27 | builder.append(input.charAt(next2)); 28 | if(remaining > 2 && isHexDigit(input.charAt(next3))) { 29 | builder.append(input.charAt(next3)); 30 | } 31 | } 32 | 33 | out.write(Integer.parseInt(builder.toString(), 16)); 34 | return 2 + builder.length(); 35 | } 36 | return 0; 37 | } 38 | 39 | private boolean isX(char ch) { 40 | return ch == 'x' || ch == 'X'; 41 | } 42 | 43 | private boolean isHexDigit(char ch) { 44 | return ch >= '0' && ch <= '7'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/util/RegexUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.util; 7 | 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | public class RegexUtils { 12 | 13 | private RegexUtils() {} 14 | 15 | public static ThreadLocal makeThreadLocalMatcher(final String regex) { 16 | return new ThreadLocal() { 17 | @Override 18 | protected Matcher initialValue() { 19 | return Pattern.compile(regex).matcher(""); 20 | } 21 | }; 22 | } 23 | 24 | public static ThreadLocal makeThreadLocalMatcher(final String regex, final int flags) { 25 | return new ThreadLocal() { 26 | @Override 27 | protected Matcher initialValue() { 28 | return Pattern.compile(regex, flags).matcher(""); 29 | } 30 | }; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/writer/BinaryWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.writer; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.util.BitArray; 10 | 11 | import java.io.DataOutputStream; 12 | import java.io.IOException; 13 | import java.io.OutputStream; 14 | 15 | public class BinaryWriter { 16 | 17 | public static void write(OutputStream outputStream, AssemblyContext context) throws WriterException { 18 | 19 | DataOutputStream dataOutputStream = new DataOutputStream(outputStream); 20 | for (BitArray assembly : context.getAssembly()) { 21 | try { 22 | dataOutputStream.writeInt(assembly.value()); 23 | } catch (IOException e) { 24 | throw new WriterException("Error writing " + String.format("%08X", assembly), e); 25 | } 26 | } 27 | 28 | try { 29 | dataOutputStream.flush(); 30 | } catch (IOException e) { 31 | throw new WriterException("Error flushing", e); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/writer/CoeWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.writer; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | import me.zhanghai.mipsasm.util.BitArray; 10 | import me.zhanghai.mipsasm.util.IoUtils; 11 | 12 | import java.io.BufferedWriter; 13 | import java.io.IOException; 14 | import java.io.OutputStream; 15 | import java.io.OutputStreamWriter; 16 | import java.nio.charset.StandardCharsets; 17 | 18 | public class CoeWriter { 19 | 20 | private static final int WORD_PER_LINE = 8; 21 | 22 | private CoeWriter() {} 23 | 24 | public static void write(OutputStream outputStream, AssemblyContext context) throws WriterException { 25 | 26 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); 27 | 28 | try { 29 | writer.write("memory_initialization_radix=16;"); 30 | writer.newLine(); 31 | writer.write("memory_initialization_vector="); 32 | writer.newLine(); 33 | } catch (IOException e) { 34 | throw new WriterException("Error writing header", e); 35 | } 36 | 37 | int wordIndex = 0; 38 | for (BitArray assembly : context.getAssembly()) { 39 | String assemblyString = IoUtils.wordToHexString(assembly.value()); 40 | try { 41 | if (wordIndex != 0) { 42 | if (wordIndex % WORD_PER_LINE == 0) { 43 | writer.write(","); 44 | writer.newLine(); 45 | } else { 46 | writer.write(", "); 47 | } 48 | } 49 | writer.write(assemblyString); 50 | ++wordIndex; 51 | } catch (IOException e) { 52 | throw new WriterException("Error writing " + assemblyString, e); 53 | } 54 | } 55 | try { 56 | writer.write(";"); 57 | writer.newLine(); 58 | } catch (IOException e) { 59 | throw new WriterException("Error writing footer", e); 60 | } 61 | 62 | try { 63 | writer.flush(); 64 | } catch (IOException e) { 65 | throw new WriterException("Error flushing", e); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/writer/DebugWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.writer; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 10 | import me.zhanghai.mipsasm.util.BitArray; 11 | import me.zhanghai.mipsasm.util.IoUtils; 12 | 13 | import java.io.BufferedWriter; 14 | import java.io.IOException; 15 | import java.io.OutputStream; 16 | import java.io.OutputStreamWriter; 17 | import java.nio.charset.StandardCharsets; 18 | 19 | public class DebugWriter { 20 | 21 | private DebugWriter() {} 22 | 23 | public static void write(OutputStream outputStream, AssemblyContext context) throws WriterException { 24 | 25 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); 26 | 27 | int address = 0; 28 | for (BitArray assembly : context.getAssembly()) { 29 | String assemblyString = IoUtils.wordToBinaryString(assembly.value()); 30 | try { 31 | if (address % Constants.BYTES_PER_WORD == 0) { 32 | if (address != 0) { 33 | writer.newLine(); 34 | } 35 | writer.write(IoUtils.wordToHexString(address)); 36 | writer.write(": "); 37 | } 38 | writer.write(assemblyString); 39 | } catch (IOException e) { 40 | throw new WriterException("Error writing " + assemblyString, e); 41 | } 42 | address += assembly.length() / Constants.BYTE_LENGTH; 43 | } 44 | 45 | try { 46 | writer.newLine(); 47 | writer.flush(); 48 | } catch (IOException e) { 49 | throw new WriterException("Error writing", e); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/writer/HexDebugWriter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.writer; 7 | 8 | import me.zhanghai.mipsasm.Constants; 9 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 10 | import me.zhanghai.mipsasm.util.BitArray; 11 | import me.zhanghai.mipsasm.util.IoUtils; 12 | 13 | import java.io.BufferedWriter; 14 | import java.io.IOException; 15 | import java.io.OutputStream; 16 | import java.io.OutputStreamWriter; 17 | import java.nio.charset.StandardCharsets; 18 | 19 | public class HexDebugWriter { 20 | 21 | private HexDebugWriter() {} 22 | 23 | public static void write(OutputStream outputStream, AssemblyContext context) throws WriterException { 24 | 25 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)); 26 | 27 | int address = 0; 28 | for (BitArray assembly : context.getAssembly()) { 29 | String assemblyString = IoUtils.wordToHexString(assembly.value()); 30 | try { 31 | if (address % (4 * Constants.BYTES_PER_WORD) == 0) { 32 | if (address != 0) { 33 | writer.newLine(); 34 | } 35 | writer.write(IoUtils.wordToHexString(address)); 36 | writer.write(":"); 37 | } 38 | writer.write(" "); 39 | writer.write(assemblyString); 40 | } catch (IOException e) { 41 | throw new WriterException("Error writing " + assemblyString, e); 42 | } 43 | address += assembly.length() / Constants.BYTE_LENGTH; 44 | } 45 | 46 | try { 47 | writer.newLine(); 48 | writer.flush(); 49 | } catch (IOException e) { 50 | throw new WriterException("Error writing", e); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/writer/Writer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.writer; 7 | 8 | import me.zhanghai.mipsasm.assembler.AssemblyContext; 9 | 10 | import java.io.OutputStream; 11 | 12 | public enum Writer { 13 | 14 | BINARY, 15 | COE, 16 | DEBUG, 17 | HEXDEBUG; 18 | 19 | public void write(OutputStream outputStream, AssemblyContext context) throws WriterException { 20 | switch (this) { 21 | case BINARY: 22 | BinaryWriter.write(outputStream, context); 23 | break; 24 | case COE: 25 | CoeWriter.write(outputStream, context); 26 | break; 27 | case DEBUG: 28 | DebugWriter.write(outputStream, context); 29 | break; 30 | case HEXDEBUG: 31 | HexDebugWriter.write(outputStream, context); 32 | break; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/me/zhanghai/mipsasm/writer/WriterException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Zhang Hai 3 | * All Rights Reserved. 4 | */ 5 | 6 | package me.zhanghai.mipsasm.writer; 7 | 8 | public class WriterException extends Exception { 9 | 10 | public WriterException() {} 11 | 12 | public WriterException(String message) { 13 | super(message); 14 | } 15 | 16 | public WriterException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public WriterException(Throwable cause) { 21 | super(cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/res/drawable/mipside_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/drawable/mipside_128.png -------------------------------------------------------------------------------- /src/res/drawable/mipside_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/drawable/mipside_16.png -------------------------------------------------------------------------------- /src/res/drawable/mipside_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/drawable/mipside_256.png -------------------------------------------------------------------------------- /src/res/drawable/mipside_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/drawable/mipside_32.png -------------------------------------------------------------------------------- /src/res/drawable/mipside_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/drawable/mipside_48.png -------------------------------------------------------------------------------- /src/res/drawable/mipside_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/drawable/mipside_512.png -------------------------------------------------------------------------------- /src/res/drawable/mipside_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/drawable/mipside_64.png -------------------------------------------------------------------------------- /src/res/font/SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/font/SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /src/res/font/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhanghai/mipsasm/c919e5ac81a4f39adfda07c655d8182497f9eccc/src/res/font/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /src/res/string/mipside.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Zhang Hai 3 | # All Rights Reserved. 4 | # 5 | 6 | app_name=MIPS Assembly IDE 7 | 8 | menu.file=&File 9 | menu.file.open=&Open…\tCtrl+O 10 | menu.file.open.filter_names=Assembly files (*.s, *.asm)|Text files (*.txt)|All files 11 | menu.file.import=&Import…\tCtrl+Alt+O 12 | menu.file.disassemble=&Disassemble…\tCtrl+Shift+O 13 | menu.file.disassemble.filter_names=Assembly output files (*.bin, *.coe)|Binary files (*.bin)|COE files(*.coe)|All files 14 | menu.file.save=&Save\tCtrl+S 15 | menu.file.save_as=Save &As…\tCtrl+Shift+S 16 | menu.file.save_as.filter_names=Assembly files (*.s)|Assembly files (*.asm)|Text files (*.txt)|All files 17 | menu.file.print=&Print…\tCtrl+P 18 | menu.file.exit=E&xit\tAlt+F4 19 | menu.edit=&Edit 20 | menu.edit.undo=&Undo\tCtrl+Z 21 | menu.edit.redo=&Redo\tCtrl+Y 22 | menu.edit.cut=Cu&t\tCtrl+Z 23 | menu.edit.copy=&Copy\tCtrl+C 24 | menu.edit.paste=&Paste\tCtrl+V 25 | menu.edit.delete=&Delete 26 | menu.edit.select_all=Select &All\tCtrl+A 27 | menu.assemble=&Assemble 28 | menu.assemble.binary=&Binary File\tF9 29 | menu.assemble.coe=&COE File\tF10 30 | menu.assemble.debug=&Debug File\tF11 31 | menu.assemble.all=&All\tF12 32 | menu.assemble.open_directory=&Open Output Directory\tF8 33 | menu.assemble.enable_delay_slot=&Enable Delay Slot 34 | menu.help=&Help 35 | menu.help.about=&About\tF1 36 | file.unsaved_document=Unsaved Document 37 | file.open_without_saving=You have unsaved changes. Are you sure to open another file? 38 | file.exit_without_saving=You have unsaved changes. Are you sure to exit? 39 | file.overwrite=File %s already exists. Overwrite? 40 | assemble.ok=Assemble saved to %s 41 | assemble.error=Error assembling %s 42 | 43 | about.title=About 44 | about.description=Developed for College of Computer Science, Zhejiang University 45 | about.website=View project on GitHub 46 | about.copyright=Copyright © 2015 Zhang Hai 47 | about.warranty=This program comes with absolutely no warranty. 48 | about.license=See the GNU General Public License, version 3 or later for details. 49 | -------------------------------------------------------------------------------- /src/res/string/mipside_zh_CN.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Zhang Hai 3 | # All Rights Reserved. 4 | # 5 | 6 | app_name=MIPS 汇编集成开发环境 7 | 8 | menu.file=文件(&F) 9 | menu.file.open=打开(&O)…\tCtrl+O 10 | menu.file.open.filter_names=汇编文件(*.s,*.asm)|文本文件(*.txt)|所有文件 11 | menu.file.import=导入(&I)…\tCtrl+Alt+O 12 | menu.file.disassemble=反汇编(&D)…\tCtrl+Shift+O 13 | menu.file.disassemble.filter_names=汇编输出文件(*.bin,*.coe)|二进制文件(*.bin)|COE 文件(*.coe)|所有文件 14 | menu.file.save=保存(&S)\tCtrl+S 15 | menu.file.save_as=另存为(&A)…\tCtrl+Shift+S 16 | menu.file.save_as.filter_names=汇编文件(*.s)|汇编文件(*.asm)|文本文件(*.txt)|所有文件 17 | menu.file.print=打印(&P)…\tCtrl+P 18 | menu.file.exit=退出(&X)\tAlt+F4 19 | menu.edit=编辑(&E) 20 | menu.edit.undo=撤销(&U)\tCtrl+Z 21 | menu.edit.redo=重做(&R)\tCtrl+Y 22 | menu.edit.cut=剪切(&T)\tCtrl+X 23 | menu.edit.copy=复制(&C)\tCtrl+C 24 | menu.edit.paste=粘贴(&P)\tCtrl+V 25 | menu.edit.delete=删除(&D) 26 | menu.edit.select_all=全选(&A)\tCtrl+A 27 | menu.assemble=汇编(&A) 28 | menu.assemble.binary=二进制文件(&B)\tF9 29 | menu.assemble.coe=COE 文件(&C)\tF10 30 | menu.assemble.debug=调试文件(&D)\tF11 31 | menu.assemble.all=全部(&A)\tF12 32 | menu.assemble.open_directory=打开输出目录(&O)\tF8 33 | menu.assemble.enable_delay_slot=启用延时槽(&E) 34 | menu.help=帮助(&H) 35 | menu.help.about=关于(&A)\tF1 36 | file.unsaved_document=未保存文档 37 | file.open_without_saving=更改尚未保存。确定要打开另一个文件吗? 38 | file.exit_without_saving=更改尚未保存。确定要退出吗? 39 | file.overwrite=文件 %s 已经存在。是否覆盖? 40 | assemble.ok=汇编结果已保存至 %s 41 | assemble.error=汇编 %s 时发生错误 42 | 43 | about.title=关于 44 | about.description=为浙江大学计算机科学与技术学院开发 45 | about.website=在 GitHub 上浏览本项目 46 | about.copyright=版权所有 © 2015 张海 47 | about.warranty=本程序无任何担保。 48 | about.license=详情见 GNU 通用公共许可证,第三版或以上。 49 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | *.coe 3 | -------------------------------------------------------------------------------- /test/hello_world.s: -------------------------------------------------------------------------------- 1 | # "Hello World" in MIPS assembly 2 | # From: http://labs.cs.upt.ro/labs/so2/html/resources/nachos-doc/mipsf.html 3 | 4 | # All program code is placed after the 5 | # .text assembler directive 6 | .text 0x0 7 | 8 | # The label 'main' represents the starting point 9 | main: 10 | # Run the print_string syscall which has code 4 11 | li $v0, 4 # Code for syscall: print_string 12 | la $a0, msg # Pointer to string (load the address of msg) 13 | syscall 14 | li $v0, 10 # Code for syscall: exit 15 | syscall 16 | 17 | # All memory structures are placed after the 18 | # .data assembler directive 19 | .data 0x20 20 | 21 | # The .asciiz assembler directive creates 22 | # an ASCII string in memory terminated by 23 | # the null character. Note that strings are 24 | # surrounded by double-quotes 25 | 26 | msg: .asciiz "Hello World!\n" 27 | -------------------------------------------------------------------------------- /test/js.s: -------------------------------------------------------------------------------- 1 | .text 1 + 3 - 4 2 | .data {eval("a = 8"), Math.floor(Math.log(Math.pow(Math.E, 4)))} 3 | .text a + 8 4 | .eval a = [-1 + 2, 2, 4 - 1] 5 | .echo "mfc" + (a[0] - 1) + " $zero, $" + a[2] 6 | -------------------------------------------------------------------------------- /test/migrate.s: -------------------------------------------------------------------------------- 1 | #baseAddr 0000 2 | j start;// 0 3 | add r0, r31, r15; //4 4 | // add $zero, $zero, $zero;//4 5 | add $zero, $zero, $zero;//8 6 | add $zero, $zero, $zero; // C 7 | add $zero, $zero, $zero; // 10 8 | add $zero, $zero, $zero; // 14 9 | add $zero, $zero, $zero; // 18 10 | add $zero, $zero, $zero; // 1C 11 | 12 | start: // 标号,可以不换行,后面直接跟代码 13 | nor $at, $zero, $zero; // r1=FFFFFFFF 14 | add $v1, $at, $at; // r3=FFFFFFFE 15 | add $v1, $v1, $v1; // r3=FFFFFFFC 16 | add $v1, $v1, $v1; // r3=FFFFFFF8 17 | add $v1, $v1, $v1; // r3=FFFFFFF0 18 | 19 | add $v1, $v1, $v1; // r3=FFFFFFE0 20 | add $v1, $v1, $v1; // r3=FFFFFFC0 21 | nor $s4, $v1, $zero;// r20=0000003F 22 | add $v1, $v1, $v1; // r3=FFFFFF80 23 | add $v1, $v1, $v1; // r3=FFFFFF00 24 | 25 | add $v1, $v1, $v1;// r3=FFFFFE00 26 | add $v1, $v1, $v1;// r3=FFFFFC00 27 | add $v1, $v1, $v1;// r3=FFFFF800 28 | add $v1, $v1, $v1;// r3=FFFFF000 29 | 30 | add $v1, $v1, $v1;// r3=FFFFE000 31 | add $v1, $v1, $v1;// r3=FFFFC000 32 | add $v1, $v1, $v1;// r3=FFFF8000 33 | add $v1, $v1, $v1;// r3=FFFF0000 34 | 35 | add $v1, $v1, $v1;// r3=FFFE0000 36 | add $v1, $v1, $v1;// r3=FFFC0000 37 | add $v1, $v1, $v1;// r3=FFF80000 38 | add $v1, $v1, $v1;// r3=FFF00000 39 | 40 | add $v1, $v1, $v1; // r3=FFE00000 41 | add $v1, $v1, $v1; // r3=FFC00000 42 | add $v1, $v1, $v1; // r3=FF800000 43 | add $v1, $v1, $v1; // r3=FF000000 44 | 45 | add $v1, $v1, $v1;// r3=FE000000 46 | add $v1, $v1, $v1;// r3=FC000000 47 | add $a2, $v1, $v1;// r6=F8000000 48 | add $v1, $a2, $a2;// r3=F0000000 49 | 50 | add $a0, $v1, $v1; // r4=E0000000 51 | 52 | add $t5, $a0, $a0; // r13=C0000000 53 | add $t0, $t5, $t5; // r8=80000000 54 | 55 | loop: // 标号,可以不换行,后面直接跟代码 56 | slt $v0, $zero, $at; // r2=00000001 57 | add $t6, $v0, $v0; 58 | add $t6, $t6, $t6; // r14=4 59 | nor $t2, $zero, $zero;// r10=FFFFFFFF 60 | add $t2, $t2, $t2; // r10=FFFFFFFE 61 | 62 | loop1: 63 | sw $a2, 4($v1); // 计数器端口:F0000004,送计数常数 r6=F8000000 64 | lw $a1, 0($v1); 65 | add $a1, $a1, $a1; // 左移 66 | add $a1, $a1, $a1; 67 | sw $a1, 0($v1); 68 | 69 | add $t1, $t1, $v0; // r9=r9+1 70 | sw $t1, 0($a0); // r9 送 r4=E0000000 七段码端口 71 | lw $t5, 14($zero); // 取存储器 20 单元预存数据至 r13,程序计数延时常数 72 | 73 | loop2: // 标号,可以不换行,后面直接跟代码 74 | lw $a1, 0($v1); // 读 GPIO 端口 F0000000 状态 75 | add $a1, $a1, $a1; 76 | add $a1, $a1, $a1; // 左移 2 位将 SW 与 LED 对齐,同时 D1D0 置 00,选择计数器 通道 0 77 | sw $a1, 0($v1); // r5 输 出 到 GPIO 端 口 F0000000,计数器通道 counter_set=00 78 | 79 | lw $a1, 0($v1); // 再读 GPIO 端口 F0000000 状态 80 | and $t3, $a1, $t0; // 取最高位=out0,屏蔽其余位送 r11 81 | // beq $t3, $t0, C_init; // out0=0,Counter 通道 0 溢出, 转计数器初始化, 修改 7 段码显示:C_init 82 | add $t5, $t5, $v0; // 程序计数延时 83 | beq $t5, $zero, C_init; // 程序计数 r13=0,转计数器初始化,修改 7 段码显示:C_init 84 | 85 | l_next: 86 | lw $a1, 0($v1); // 判断 7 段码显示模式:SW[4:3]控制 87 | add $s2, $t6, $t6; // 再读 GPIO 端口 F0000000 开关 SW 状态 88 | add $s6, $s2, $s2; // r14=4,r18=00000008 89 | add $s2, $s2, $s6; // r22=00000010 90 | and $t3, $a1, $s2; // r18=00000018(00011000) 91 | beq $t3, $zero, L20;// 取 SW[4:3] 92 | beq $t3, $s2, L21; // SW[4:3]=00,7 段显示"点"循环移位:L20, SW0=0 93 | add $s2, $t6, $t6; // SW[4:3]=11,显示七段图形,L21,SW0=0 94 | beq $t3, $s2, L22; // r18=8 95 | sw $t1, 0($a0); // SW[4:3]=01, 七段显示预置数字,L22, SW0=1 96 | j loop2; // SW[4:3]=10,显示 r9,SW0=1 97 | 98 | L20: 99 | beq $t2, $at, L4; 100 | j L3; // r10=ffffffff,转移 L4 101 | 102 | 103 | L4: 104 | nor $t2, $zero, $zero; // r10=ffffffff 105 | add $t2, $t2, $t2; // r10=fffffffe 106 | 107 | L3: 108 | sw $t2, 0($a0); // SW[4:3]=00,7 段显示点移位后显示 109 | j loop2; 110 | 111 | L21: 112 | lw $t1, 60($s1); // SW[4:3]=11,从内存取预存七段图形 113 | sw $t1, 0($a0); // SW[4:3]=11,显示七段图形 114 | j loop2; 115 | 116 | L22: 117 | lw $t1, 20($s1); // SW[4:3]=01,从内存取预存数字 118 | sw $t1, 0($a0); // SW[4:3]=01,七段显示预置数字 119 | j loop2; 120 | 121 | C_init: 122 | lw $t5, 14($zero); // 取程序计数延时初始化常数 123 | add $t2, $t2, $t2; // r10=fffffffc,7 段图形点左移 124 | or $t2, $t2, $v0; // r10 末位置 1,对应右上角不显示 125 | add $s1, $s1, $t6; // r17=00000004,LED 图形访存地址+4 126 | and $s1, $s1, $s4; // r17=000000XX,屏蔽地址高位,只取 6 位 add $t1, $t1, $v0 127 | add $t1, $t1, $v0; // r9+1 128 | beq $t1, $at, L6; // 若 r9=ffffffff,重置 r9=5 129 | j L7; 130 | 131 | L6: 132 | add $t1, $zero, $t6; // r9=4 133 | add $t1, $t1, $v0; // 重置 r9=5 134 | 135 | L7: 136 | lw $a1, 0($v1); // 读 GPIO 端口 F0000000 状态 137 | add $t3, $a1, $a1; 138 | add $t3, $t3, $t3; // 左移 2 位将 SW 与 LED 对齐,同时 D1D0 置 00,选择计数器通道 0 139 | sw $t3, 0($v1); // r5 输出到 GPIO 端口 F0000000,计数器通道 counter_set=00 140 | sw $a2, 4($v1); // 计数器端口:F0000004,送计数常数 r6=F8000000 141 | 142 | j l_next; 143 | // 从此处-0000FFFC 填“00000000”。 144 | 145 | #DataAddre: 00001000; // 数据地址,此处 00001000H 开始定义数据 146 | Data1: // 数据区 1, 标号 147 | dd 0xFFFFFF00, 0x000002AB, 0x80000000, 0x0000003F, 0x00000001, 0xFFFF0000, 0x0000FFFF, 0x80000000, 0x00000000, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD, 0xEEEEEEEE, 0xFFFFFFFF; 148 | db 0x55, 0x56, 0x57, 0x58; // db伪指令,定义数据0x55...在00001060 149 | dw 'ab', 0x1234;// dw伪指令,定义数据0x41, 0x42, 0x1234在000010604 150 | dd 0x12345678; // dd伪指令,定义数据0x12345678在00001068 151 | 152 | data2: 153 | RESB 16; // data2是标号,从0000106C开始定义16个字节空间 154 | // 此处 00001070-00001FFC 填“00000000”。 155 | 156 | #DataAddre: 00002000; // 数据地址,此处 00002000H 开始定义数据 157 | Data2: // 数据区 2, 标号 158 | dd 0x557EF7E0, 0xD7BDFBD9, 0xD7DBFDB9, 0xDFCFFCFB, 0xDFCFBFFF, 0xF7F3DFFF, 0xFFFFDF3D, 0xFFFF9DB9, 0XFFFFBCFB, 0XDFCFFCFB, 0XDFCFBFFF, 0XD7DB9FFF, 0XD7DBFDB9, 0XD7BDFBD9, 0XFFFF07E0, 0X007E0FFF, 0X03BDF020, 0X03DEF820, 0X08002300; 159 | // 此处从0000204C-0000BFFC填“00000000”。 160 | 161 | #DataAddre: 0x0000C000; // 数据地址,此处0000C000H开始定义数据 162 | buffer: 163 | RESD 32; // 数据区3,buffer标号=0000C000,定义32个32位字空间,到 0000C080 结束 164 | -------------------------------------------------------------------------------- /test/test.s: -------------------------------------------------------------------------------- 1 | .text 0x00000000 2 | j start; // 0 3 | add $zero, $zero, $zero; // 4 4 | add $zero, $zero, $zero; // 8 5 | add $zero, $zero, $zero; // C 6 | add $zero, $zero, $zero; // 10 7 | add $zero, $zero, $zero; // 14 8 | add $zero, $zero, $zero; // 18 9 | add $zero, $zero, $zero; // 1C 10 | 11 | start: // 标号,可以不换行,后面直接跟代码 12 | nor $at, $zero, $zero; // r1=FFFFFFFF 13 | add $v1, $at, $at; // r3=FFFFFFFE 14 | add $v1, $v1, $v1; // r3=FFFFFFFC 15 | add $v1, $v1, $v1; // r3=FFFFFFF8 16 | add $v1, $v1, $v1; // r3=FFFFFFF0 17 | 18 | add $v1, $v1, $v1; // r3=FFFFFFE0 19 | add $v1, $v1, $v1; // r3=FFFFFFC0 20 | nor $s4, $v1, $zero;// r20=0000003F 21 | add $v1, $v1, $v1; // r3=FFFFFF80 22 | add $v1, $v1, $v1; // r3=FFFFFF00 23 | 24 | add $v1, $v1, $v1;// r3=FFFFFE00 25 | add $v1, $v1, $v1;// r3=FFFFFC00 26 | add $v1, $v1, $v1;// r3=FFFFF800 27 | add $v1, $v1, $v1;// r3=FFFFF000 28 | 29 | add $v1, $v1, $v1;// r3=FFFFE000 30 | add $v1, $v1, $v1;// r3=FFFFC000 31 | add $v1, $v1, $v1;// r3=FFFF8000 32 | add $v1, $v1, $v1;// r3=FFFF0000 33 | 34 | add $v1, $v1, $v1;// r3=FFFE0000 35 | add $v1, $v1, $v1;// r3=FFFC0000 36 | add $v1, $v1, $v1;// r3=FFF80000 37 | add $v1, $v1, $v1;// r3=FFF00000 38 | 39 | add $v1, $v1, $v1; // r3=FFE00000 40 | add $v1, $v1, $v1; // r3=FFC00000 41 | add $v1, $v1, $v1; // r3=FF800000 42 | add $v1, $v1, $v1; // r3=FF000000 43 | 44 | add $v1, $v1, $v1;// r3=FE000000 45 | add $v1, $v1, $v1;// r3=FC000000 46 | add $a2, $v1, $v1;// r6=F8000000 47 | add $v1, $a2, $a2;// r3=F0000000 48 | 49 | add $a0, $v1, $v1; // r4=E0000000 50 | 51 | add $t5, $a0, $a0; // r13=C0000000 52 | add $t0, $t5, $t5; // r8=80000000 53 | 54 | loop: // 标号,可以不换行,后面直接跟代码 55 | slt $v0, $zero, $at; // r2=00000001 56 | add $t6, $v0, $v0; 57 | add $t6, $t6, $t6; // r14=4 58 | nor $t2, $zero, $zero;// r10=FFFFFFFF 59 | add $t2, $t2, $t2; // r10=FFFFFFFE 60 | 61 | loop1: 62 | sw $a2, 4($v1); // 计数器端口:F0000004,送计数常数 r6=F8000000 63 | lw $a1, 0($v1); 64 | add $a1, $a1, $a1; // 左移 65 | add $a1, $a1, $a1; 66 | sw $a1, 0($v1); 67 | 68 | add $t1, $t1, $v0; // r9=r9+1 69 | sw $t1, 0($a0); // r9 送 r4=E0000000 七段码端口 70 | lw $t5, 14($zero); // 取存储器 20 单元预存数据至 r13,程序计数延时常数 71 | 72 | loop2: // 标号,可以不换行,后面直接跟代码 73 | lw $a1, 0($v1); // 读 GPIO 端口 F0000000 状态 74 | add $a1, $a1, $a1; 75 | add $a1, $a1, $a1; // 左移 2 位将 SW 与 LED 对齐,同时 D1D0 置 00,选择计数器 通道 0 76 | sw $a1, 0($v1); // r5 输 出 到 GPIO 端 口 F0000000,计数器通道 counter_set=00 77 | 78 | lw $a1, 0($v1); // 再读 GPIO 端口 F0000000 状态 79 | and $t3, $a1, $t0; // 取最高位=out0,屏蔽其余位送 r11 80 | // beq $t3, $t0, C_init; // out0=0,Counter 通道 0 溢出, 转计数器初始化, 修改 7 段码显示:C_init 81 | add $t5, $t5, $v0; // 程序计数延时 82 | beq $t5, $zero, C_init; // 程序计数 r13=0,转计数器初始化,修改 7 段码显示:C_init 83 | 84 | l_next: 85 | lw $a1, 0($v1); // 判断 7 段码显示模式:SW[4:3]控制 86 | add $s2, $t6, $t6; // 再读 GPIO 端口 F0000000 开关 SW 状态 87 | add $s6, $s2, $s2; // r14=4,r18=00000008 88 | add $s2, $s2, $s6; // r22=00000010 89 | and $t3, $a1, $s2; // r18=00000018(00011000) 90 | beq $t3, $zero, L20;// 取 SW[4:3] 91 | beq $t3, $s2, L21; // SW[4:3]=00,7 段显示"点"循环移位:L20, SW0=0 92 | add $s2, $t6, $t6; // SW[4:3]=11,显示七段图形,L21,SW0=0 93 | beq $t3, $s2, L22; // r18=8 94 | sw $t1, 0($a0); // SW[4:3]=01, 七段显示预置数字,L22, SW0=1 95 | j loop2; // SW[4:3]=10,显示 r9,SW0=1 96 | 97 | L20: 98 | beq $t2, $at, L4; 99 | j L3; // r10=ffffffff,转移 L4 100 | 101 | 102 | L4: 103 | nor $t2, $zero, $zero; // r10=ffffffff 104 | add $t2, $t2, $t2; // r10=fffffffe 105 | 106 | L3: 107 | sw $t2, 0($a0); // SW[4:3]=00,7 段显示点移位后显示 108 | j loop2; 109 | 110 | L21: 111 | lw $t1, 60($s1); // SW[4:3]=11,从内存取预存七段图形 112 | sw $t1, 0($a0); // SW[4:3]=11,显示七段图形 113 | j loop2; 114 | 115 | L22: 116 | lw $t1, 20($s1); // SW[4:3]=01,从内存取预存数字 117 | sw $t1, 0($a0); // SW[4:3]=01,七段显示预置数字 118 | j loop2; 119 | 120 | C_init: 121 | lw $t5, 14($zero); // 取程序计数延时初始化常数 122 | add $t2, $t2, $t2; // r10=fffffffc,7 段图形点左移 123 | or $t2, $t2, $v0; // r10 末位置 1,对应右上角不显示 124 | add $s1, $s1, $t6; // r17=00000004,LED 图形访存地址+4 125 | and $s1, $s1, $s4; // r17=000000XX,屏蔽地址高位,只取 6 位 add $t1, $t1, $v0 126 | add $t1, $t1, $v0; // r9+1 127 | beq $t1, $at, L6; // 若 r9=ffffffff,重置 r9=5 128 | j L7; 129 | 130 | L6: 131 | add $t1, $zero, $t6; // r9=4 132 | add $t1, $t1, $v0; // 重置 r9=5 133 | 134 | L7: 135 | lw $a1, 0($v1); // 读 GPIO 端口 F0000000 状态 136 | add $t3, $a1, $a1; 137 | add $t3, $t3, $t3; // 左移 2 位将 SW 与 LED 对齐,同时 D1D0 置 00,选择计数器通道 0 138 | sw $t3, 0($v1); // r5 输出到 GPIO 端口 F0000000,计数器通道 counter_set=00 139 | sw $a2, 4($v1); // 计数器端口:F0000004,送计数常数 r6=F8000000 140 | 141 | j l_next; 142 | // 从此处-0000FFFC 填“00000000”。 143 | 144 | .data 0x00001000; // 数据地址,此处 00001000H 开始定义数据 145 | Data1: // 数据区 1, 标号 146 | .word 0xFFFFFF00, 0x000002AB, 0x80000000, 0x0000003F, 0x00000001, 0xFFFF0000, 0x0000FFFF, 0x80000000, 0x00000000, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD, 0xEEEEEEEE, 0xFFFFFFFF; 147 | .byte 0x55, 0x56, 0x57, 0x58; // db伪指令,定义数据0x55...在00001060 148 | .ascii "ab"; 149 | .half 0x1234;// dw伪指令,定义数据0x41, 0x42, 0x1234在000010604 150 | .word 0x12345678; // dd伪指令,定义数据0x12345678在00001068 151 | 152 | data2: 153 | .space 16; // data2是标号,从0000106C开始定义16个字节空间 154 | // 此处 00001070-00001FFC 填“00000000”。 155 | 156 | .data 0x00002000; // 数据地址,此处 00002000H 开始定义数据 157 | Data2: // 数据区 2, 标号 158 | .word 0x557EF7E0, 0xD7BDFBD9, 0xD7DBFDB9, 0xDFCFFCFB, 0xDFCFBFFF, 0xF7F3DFFF, 0xFFFFDF3D, 0xFFFF9DB9, 0XFFFFBCFB, 0XDFCFFCFB, 0XDFCFBFFF, 0XD7DB9FFF, 0XD7DBFDB9, 0XD7BDFBD9, 0XFFFF07E0, 0X007E0FFF, 0X03BDF020, 0X03DEF820, 0X08002300; 159 | // 此处从0000204C-0000BFFC填“00000000”。 160 | 161 | .data 0x0000C000; // 数据地址,此处0000C000H开始定义数据 162 | buffer: 163 | .space 128; // 数据区3,buffer标号=0000C000,定义32个32位字空间,到 0000C080 结束 164 | --------------------------------------------------------------------------------