├── .eslintrc.json ├── .github ├── DISCUSSION_TEMPLATE │ ├── announcements.yml │ └── todos.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_proposal.yml ├── pull_request_template.md └── workflows │ ├── ci.yml │ ├── coverage.yml │ └── npm-publish.yml ├── .gitignore ├── .gitmessage.txt ├── .npmignore ├── .prettierrc.json ├── COMMIT_README.md ├── README.md ├── babel.config.json ├── index.ts ├── jest.config.json ├── package-lock.json ├── package.json ├── sample_input ├── example01.o ├── example1.s ├── example2.s ├── example3.s ├── example4.s ├── example5.s ├── example6.s └── example7.s ├── sample_output ├── example1.o ├── example2.o ├── example3.o ├── example4.o ├── example5.o ├── example6.o └── example7.o ├── simulator_sample_output ├── example01.o ├── example02.o ├── example03.o ├── example04.o ├── example05.o ├── example06.o └── example07.o ├── src ├── simulator │ ├── assembler.ts │ └── run.ts └── utils │ ├── constants.ts │ └── functions.ts ├── tests ├── integration │ ├── assembler.test.ts │ └── simulator.test.ts └── unit │ ├── makeSymbolTable.test.ts │ ├── recordDataSection.test.ts │ └── recordTextSection.test.ts ├── tsconfig.json └── typescript.eslintrc.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended", 9 | "plugin:@typescript-eslint/recommended-requiring-type-checking", 10 | "plugin:prettier/recommended" 11 | ], 12 | "overrides": [], 13 | "parser": "@typescript-eslint/parser", 14 | "plugins": ["@typescript-eslint", "import"], 15 | "parserOptions": { 16 | "project": "./tsconfig.json", 17 | "ecmaVersion": "latest", 18 | "sourceType": "module" 19 | }, 20 | "root": true, 21 | "rules": { 22 | "semi": [2, "always"], 23 | "@typescript-eslint/no-unused-vars": [ 24 | "warn", // or "error" 25 | { 26 | "argsIgnorePattern": "^_", 27 | "varsIgnorePattern": "^_", 28 | "caughtErrorsIgnorePattern": "^_" 29 | } 30 | ] 31 | }, 32 | "ignorePatterns": ["dist/", "node_modules/", "coverage/"], 33 | "settings": { 34 | "import/resolver": { 35 | "typescript": {} 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/announcements.yml: -------------------------------------------------------------------------------- 1 | title: '[Announcement] ' 2 | labels: ['Announcement'] 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | Announcement 8 | - type: textarea 9 | id: improvements and changes 10 | attributes: 11 | label: Top 3 improvements and changes 12 | description: 'What are the top 3 improvements we could make to this project?' 13 | value: | 14 | 1. 15 | 2. 16 | 3. 17 | ... 18 | render: bash 19 | validations: 20 | required: true 21 | - type: markdown 22 | attributes: 23 | value: | 24 | ## Additional 25 | And some more additionals 26 | - type: input 27 | id: has-id 28 | attributes: 29 | label: Suggestions 30 | description: A description about suggestions to help you 31 | validations: 32 | required: true 33 | - type: dropdown 34 | id: download 35 | attributes: 36 | label: Which area of this project could be most improved? 37 | options: 38 | - Documentation 39 | - New Features 40 | - Pull request review time 41 | - testing improvements 42 | - Bug fix time 43 | - Release cadence 44 | validations: 45 | required: true 46 | - type: checkboxes 47 | attributes: 48 | label: new release version 49 | options: 50 | - label: yes, it has deployed with new version 51 | - label: no, it's not version change 52 | -------------------------------------------------------------------------------- /.github/DISCUSSION_TEMPLATE/todos.yml: -------------------------------------------------------------------------------- 1 | title: '[TODO] ' 2 | labels: ['TODO'] 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | TODO 8 | - type: textarea 9 | id: TODO 10 | attributes: 11 | label: TODOS with main points and conditions 12 | description: 'TODOS with main points with 3 conditions' 13 | value: | 14 | 15 | ## [main points] 16 | 17 | > what you have to do 18 | 19 | 1. 20 | 2. 21 | 3. 22 | ... 23 | 24 | ## [conditions] 25 | 26 | > follow these condition 27 | 28 | 1. if features are added, it should have test code with jest (unit test, integration test). 29 | 2. if it has changes with previous version, it should be written in README.md. 30 | 3. if it fix buges, describe which bug is found, and how solve it. 31 | ... 32 | 33 | render: markdown 34 | validations: 35 | required: true 36 | - type: dropdown 37 | id: download 38 | attributes: 39 | label: which category? 40 | options: 41 | - Documentation 42 | - New Features 43 | - Pull request review time 44 | - testing improvements 45 | - Bug fix time 46 | - Release cadence 47 | validations: 48 | required: true 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 🪲 2 | description: Create a bug report to help us improve 3 | title: '[Bug]: ' 4 | labels: ['🐞 Bug Report'] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | ### Please provide all the information requested. Issues that do not follow this format are likely to stall. 10 | --- 11 | - type: input 12 | id: version 13 | attributes: 14 | label: Version 15 | description: | 16 | The version of Mips-simulator-js you are using. 17 | Is it the [latest](https://github.com/mipsSimulatorUNIST/simulator/tree/release)? Test and see if the bug has already been fixed. 18 | placeholder: ex. 2.1.9 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: reproduction 23 | attributes: 24 | label: Steps to reproduce 25 | description: Provide a detailed list of steps that reproduce the issue. 26 | placeholder: 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: behavior 31 | attributes: 32 | label: Expected and Actual behavior 33 | description: A description of what you expect to happen. A clear and concise description of the unexpected behavior. 34 | placeholder: I expect to see X or Y, but A bug happened! 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: context 39 | attributes: 40 | label: Additional context 41 | description: Anything else that might be relevant 42 | validations: 43 | required: false 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_proposal.yml: -------------------------------------------------------------------------------- 1 | name: Feature Proposal 🚀 2 | description: Submit a proposal for a new feature 3 | title: '[Feature]: ' 4 | labels: [':rocket: Feature Proposal'] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | ### Thank you for taking the time to suggest a new feature! 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: '🚀 Feature Proposal' 14 | description: A clear and concise description of what the feature is. 15 | validations: 16 | required: true 17 | - type: textarea 18 | id: solution 19 | attributes: 20 | label: Motivation 21 | description: Outline your motivation for the proposal. How will it make mips-simulator-js better? 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: alternatives 26 | attributes: 27 | label: Example 28 | description: Describe how this feature would be used. 29 | validations: 30 | required: false 31 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## ISSUE <#00> {이슈 이름} 2 | 여기에 이슈에 대해서 간단하게 설명해주세요 3 | 4 | 5 |
6 | 7 | ## CHANGES 8 | 어떤 코드를 만들었는지 혹은 어떤 코드를 수정해서 문제를 해결했는지 적어주세요 9 | 10 | 11 |
12 | 13 | ## TEST 14 | 어떤 부분을 테스트 해보면 좋을지 어떻게 테스트하면 되는지 간단하게 설명해주세요 15 | 16 | ## EX 17 | 예시 사진이 있다면 여기에 첨부해주세요 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | # 구독할 이벤트 4 | on: 5 | push: 6 | branches: [main] 7 | pull_request: 8 | branches: [main] 9 | 10 | # jobs 단위로 개별 서버(정확히는 Docker 컨테이너 단위라고 한다.)에서 작업이 수행된다. 11 | # 각 작업은 병렬로 실행 된다고 하는데, needs: build와 같이 표시해서 기다릴 수도 있다. 12 | jobs: 13 | build: 14 | # Ubuntu, Windows, MacOS를 지원한다. 15 | runs-on: ubuntu-latest 16 | 17 | # node-version 과 같이 배열로 돼있으면, 해당 원소를 순회하면서 작업이 반복해서 실행된다. 18 | # 응용해서 runs-on에 여러 OS에서 돌릴 수도 있다. 19 | strategy: 20 | matrix: 21 | node-version: [14.x] # 템플릿 기본값: [10.x, 12.x, 14.x] 22 | 23 | # uses 개념은 다른 사람이 작성한 내용을 실행하는 개념이다. 24 | # actions/checkout: GitHub의 마지막 커밋으로 Checkout 한다. 25 | # actions/setup-node: Node.js를 설치한다. 26 | # run 개념은 명령어를 실행한다. 셸 스크립트와 동일하다. 27 | steps: 28 | - uses: actions/checkout@v2 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v1 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | # npm ci는 npm install과 같은 기능을 수행한다. 34 | - run: npm ci 35 | # --if-present 옵션은 npm 스크립트가 존재할 때만 실행시키라는 의미이다. 36 | # 만약 build 스크립트가 없는 경우, 오류 없이 지나간다. 37 | - run: npm run build --if-present 38 | - run: npm run lint 39 | - run: npm test -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy Coverage content to Pages 3 | 4 | on: 5 | workflow_dispatch: 6 | push: 7 | branches: ['main'] 8 | 9 | concurrency: 10 | group: 'pages' 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: actions/configure-pages@v2 19 | - uses: actions/setup-node@v3 20 | with: 21 | node-version: 16 22 | - run: npm ci --legacy-peer-deps 23 | - run: npm run pre-test 24 | env: 25 | CI: false 26 | - name: Upload pages artifact 27 | uses: actions/upload-pages-artifact@v1 28 | with: 29 | path: './coverage/lcov-report' 30 | 31 | deploy: 32 | needs: build 33 | permissions: 34 | pages: write 35 | id-token: write 36 | environment: 37 | name: github-pages 38 | url: ${{ steps.deployment.outputs.page_url }} 39 | runs-on: ubuntu-latest 40 | steps: 41 | - name: Deploy to GitHub Pages 42 | id: deployment 43 | uses: actions/deploy-pages@v1 44 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: npm publish 2 | 3 | on: 4 | release: 5 | types: [created] 6 | branches: 7 | - main 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: actions/setup-node@v3 15 | with: 16 | node-version: 16 17 | - name: Delete node_modules and package-lock.json 18 | run: rm -rf node_modules package-lock.json 19 | - name: Clear npm cache 20 | run: npm cache clean --force 21 | - name: Install yocto-queue as a direct dependency 22 | run: npm install yocto-queue --save 23 | - name: Install dependencies 24 | run: npm install 25 | - name: Run tests 26 | run: npm run pre-test 27 | 28 | publish-npm: 29 | needs: build 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v3 33 | - uses: actions/setup-node@v3 34 | with: 35 | node-version: 16 36 | registry-url: https://registry.npmjs.org/ 37 | - name: Delete node_modules and package-lock.json 38 | run: rm -rf node_modules package-lock.json 39 | - name: Clear npm cache 40 | run: npm cache clean --force 41 | - name: Install yocto-queue as a direct dependency 42 | run: npm install yocto-queue --save 43 | - name: Install dependencies 44 | run: npm install 45 | - name: Publish package to npm 46 | run: npm run publish-npm 47 | env: 48 | NODE_AUTH_TOKEN: ${{secrets.mips_token}} 49 | 50 | sync-release: 51 | needs: publish-npm 52 | 53 | runs-on: ubuntu-latest 54 | steps: 55 | - name: Checkout 56 | uses: actions/checkout@v2 57 | with: 58 | ref: main 59 | 60 | - name: Merge release to main 61 | uses: devmasx/merge-branch@master 62 | with: 63 | type: now 64 | from_branch: main 65 | target_branch: release 66 | github_token: ${{ github.token }} 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # node.js 2 | # 3 | coverage/ 4 | node_modules/ 5 | npm-debug.log 6 | yarn-error.log 7 | 8 | dist/ 9 | .DS_Store -------------------------------------------------------------------------------- /.gitmessage.txt: -------------------------------------------------------------------------------- 1 | ################ 2 | # UNIST MIPS SIMULATOR GIT MESSAGE TEMPLATE 3 | # [커밋 타입 종류] 4 | # feat : 새로운 기능 추가 5 | # fix : 버그 수정 6 | # docs : 문서 수정 7 | # test : 테스트 코드 추가 8 | # refact : 코드 리팩토링 9 | # style : 코드 의미에 영향을 주지 않는 변경사항 10 | # chore : 빌드 부분 혹은 패키지 매니저 수정사항 11 | ################ 12 | 13 | # '#' 라인은 주석입니다. 14 | # [#Issue Number] <타입> : <제목> 의 형식으로 제목을 아래 공백줄에 작성 15 | # 제목은 50자 이내 / 변경사항이 "무엇"인지 명확히 작성 / 끝에 마침표 금지 16 | # 예) feat : 로그인 기능 추가 17 | # [#Issue Number]를 커밋메세지 앞에 추가하면 이슈별로 커밋을 관리할 수 있음 18 | # --이 라인 밑에 "[#Issue Number] <타입> : <제목>" 작성해주세요-- 19 | 20 | # 바로 아래 공백은 지우지 마세요 (제목과 본문의 분리를 위함) 21 | 22 | ################ 23 | # 본문(구체적인 내용)을 아랫줄에 작성 24 | # 여러 줄의 메시지를 작성할 땐 "-"로 구분 (한 줄은 72자 이내) 25 | # --이 라인 밑에 "본문" 작성해주세요-- 26 | 27 | ################ 28 | # 꼬릿말(footer)을 아랫줄에 작성 (현재 커밋과 관련된 이슈 번호 추가 등) 29 | # 예) Close #7 30 | # --이 라인 밑에 "꼬릿말" 작성해주세요-- 31 | 32 | ################ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | src/ 3 | coverage/ 4 | .github/ 5 | tests/ 6 | .eslintrc.json 7 | .gitignore 8 | .gitmessage.txt 9 | .prettierrc.json 10 | babel.config.json 11 | COMMIT_README.md 12 | index.ts 13 | tsconfig.json 14 | typescript.eslintrc.json 15 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": false, 3 | "jsxBracketSameLine": true, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma": "all", 7 | "arrowParens": "avoid", 8 | "endOfLine": "auto", 9 | "tabWidth": 2 10 | } 11 | -------------------------------------------------------------------------------- /COMMIT_README.md: -------------------------------------------------------------------------------- 1 | # GIT Message Template 2 | 3 | ## .gitmessage.txt 4 | 커밋 시 Git은 commit.template 옵션에 설정한 템플릿 파일을 보여준다. 5 | 6 | 커밋 메시지 템플릿을 지정하면 커밋 메시지를 작성할 때 일정한 스타일을 유지할 수 있다. 7 | 8 | .gitmessage.txt 파일은 아래와 같이 구성되어있으며, 커밋시에 적용됩니다. 9 | 10 | + [#Issue Number]를 커밋메세지 앞에 추가하면 이슈별로 커밋을 관리할 수 있음 11 | 12 | ``` 13 | ################ 14 | # UNIST MIPS SIMULATOR GIT MESSAGE TEMPLATE 15 | # [커밋 타입 종류] 16 | # feat : 새로운 기능 추가 17 | # fix : 버그 수정 18 | # docs : 문서 수정 19 | # test : 테스트 코드 추가 20 | # refact : 코드 리팩토링 21 | # style : 코드 의미에 영향을 주지 않는 변경사항 22 | # chore : 빌드 부분 혹은 패키지 매니저 수정사항 23 | ################ 24 | 25 | # '#' 라인은 주석입니다. 26 | # [#Issue Number] <타입> : <제목> 의 형식으로 제목을 아래 공백줄에 작성 27 | # 제목은 50자 이내 / 변경사항이 "무엇"인지 명확히 작성 / 끝에 마침표 금지 28 | # 예) feat : 로그인 기능 추가 29 | # --이 라인 밑에 "[#Issue Number] <타입> : <제목>" 작성해주세요-- 30 | 31 | # 바로 아래 공백은 지우지 마세요 (제목과 본문의 분리를 위함) 32 | 33 | ################ 34 | # 본문(구체적인 내용)을 아랫줄에 작성 35 | # 여러 줄의 메시지를 작성할 땐 "-"로 구분 (한 줄은 72자 이내) 36 | # --이 라인 밑에 "본문" 작성해주세요-- 37 | 38 | ################ 39 | # 꼬릿말(footer)을 아랫줄에 작성 (현재 커밋과 관련된 이슈 번호 추가 등) 40 | # 예) Close #7 41 | # --이 라인 밑에 "꼬릿말" 작성해주세요-- 42 | 43 | ################ 44 | ``` 45 | 46 | ## 적용 방법 47 | ### 템플릿 파일 설정 48 | 템플릿 파일을 설정해놓으면, git commit 명령을 실행할 때 지정한 템플릿 메시지를 편집기에서 매번 사용할 수 있다. 49 | 50 | 템플릿 파일을 설정한다는 것은 commit.template에 .gitmessage.txt 파일을 등록한다는 의미다. 51 | 52 | 템플릿 파일을 설정하는 명령은 아래와 같다. 53 | 54 | ``` 55 | git config --global commit.template .gitmessage.txt 56 | ``` 57 | ---- 58 | 59 | ### 에디터 사용 방법 60 | ``` 61 | git add . 62 | git commit 63 | ``` 64 | 위 명령어를 사용하면 변경된 파일들을 스테이지에 올리고 commit을 실행한다. 65 | 66 | 이후 설정된 template이 터미널 에디터에 출력되고, 67 | 68 | ' i '를 눌러 INSERT 모드로 변경한다. 69 | 70 | 변경한 후에는 71 | 72 | ``` 73 | ESC + :wq! + ENTER 74 | ``` 75 | 76 | 를 통해 커밋 메세지 저장 후 커밋을 완료할 수 있다. 77 | 78 | 만약 commit 메세지 작성 중 commit을 취소하고 싶다면, 79 | 80 | ``` 81 | ESC + :qa + ENTER 82 | ``` 83 | 를 통해 commit 작업을 취소할 수 있다. 84 | 85 | ---- 86 | 87 | ## Reference 88 | https://velog.io/@bky373/Git-%EC%BB%A4%EB%B0%8B-%EB%A9%94%EC%8B%9C%EC%A7%80-%ED%85%9C%ED%94%8C%EB%A6%BF -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIPS Simulator 2 | 3 | ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/mipsSimulatorUNIST/simulator/ci.yml?style=plastic) 4 | ![Weekly Downloads](https://img.shields.io/npm/dw/mips-simulator-js?style=plastic) 5 | ![version](https://img.shields.io/npm/v/mips-simulator-js?style=plastic) 6 | ![types](https://img.shields.io/npm/types/mips-simulator-js?style=plastic) 7 | 8 | You can use Node.js MIPS Simulator with [npm](https://www.npmjs.com/package/mips-simulator-js) 9 | 10 | [_Git Repository_ →](https://github.com/mipsSimulatorUNIST/simulator) 11 | 12 | [_Coverage Status_ →](https://mipssimulatorunist.github.io/simulator/) 13 | 14 | 15 | [demo simulator→](https://mipssimulatorunist.github.io/reactGUI/simulator) 16 | 17 | ![ezgif com-video-to-gif (1)](https://user-images.githubusercontent.com/44657722/224466039-b06823a0-d8cd-4e3e-aa2b-4b9fb8602e51.gif) 18 | 19 | > ⚠️ [Changes](#changes) 20 | > 21 | > Example code in this document is working in `>= version 2.1.5` 22 | > 23 | > if you are using previous version, please read ⚠️ [Changes](#changes) 24 | 25 | ## Introduction 26 | 27 | This open source provides functions to implement MIPS simulation in node.js environment. 28 | 29 | We currently support functions that 30 | [assembler - convert an assembly file to a binary file](#assembler) 31 | and 32 | [simulator - simulate actual assembly files](#simulator). 33 | 34 | ## Installation 35 | 36 | ```bash 37 | $ npm install --save mips-simulator-js 38 | ``` 39 | 40 | ## assembler 41 | 42 | > assemble provides some functions for making binary file to assembly file. 43 | 44 | ### makeInput 45 | 46 | function for parsing `binary file` to `string array`. 47 | 48 | ```typescript 49 | export function makeInput(inputFolderName: string, inputFileName : string) { 50 | return assemblyInput : string[] 51 | } 52 | ``` 53 | 54 | ### makeObjectFile 55 | 56 | function for making file from `string array` to `binary file`. 57 | 58 | ```typescript 59 | export function makeObjectFile( 60 | outputFolderPath: string, 61 | outputFileName: string, 62 | content: string[], 63 | ) { 64 | return; 65 | // make .o file to outputFolderPath 66 | } 67 | ``` 68 | 69 | ### assemble 70 | 71 | function for convert `assembly instructions` to `binary instructions`. 72 | 73 | > #### >= version 2.1.5 74 | > 75 | > `arrayOutputType` has deleted, assemble function only return string[] as output. 76 | 77 | > #### >= version 2.1.0 78 | > 79 | > `arrayOutputType` : if you want to get output with string, it should be false (default : true (string array)) 80 | > 81 | > `mappingDetailRequest`: if you want to get mapping data (which assembly instruction map into specific binary instruction), it should be true (default : false) 82 | 83 | ```typescript 84 | interface IAssemble { 85 | output: string[]; 86 | mappingDetail: IMapDetail[] | null; 87 | } 88 | 89 | export function assemble = ( 90 | assemblyInstructions: string[], 91 | mappingDetailRequest = false 92 | ) { 93 | ... 94 | return {output, mappingDetail} : IAssemble 95 | }; 96 | ``` 97 | 98 | > **Mapping Detail Sample** 99 | > 100 | > ```typescript 101 | > const mappingDetailOutput: IMapDetail[] = [ 102 | > { 103 | > key: 0, 104 | > assembly: "\t.data", 105 | > binary: [{ lineNumber: 0, data: "00000000000000000000000001011000" }], 106 | > }, 107 | > { 108 | > key: 1, 109 | > assembly: "data1:\t.word\t100", 110 | > binary: [{ lineNumber: 24, data: "00000000000000000000000001100100" }], 111 | > }, 112 | > ...{ 113 | > key: 6, 114 | > assembly: '\tand\t$17, $17, $0', 115 | > binary: [{lineNumber: 2, data: '00000010001000001000100000100100'}], 116 | > }, 117 | > { 118 | > key: 7, 119 | > assembly: '\tand\t$18, $18, $0', 120 | > binary: [{lineNumber: 3, data: '00000010010000001001000000100100'}], 121 | > }, 122 | > ...{ 123 | > key: 9, 124 | > assembly: '\tla\t$9, data2', 125 | > binary: [ 126 | > {lineNumber: 5, data: '00111100000010010001000000000000'}, 127 | > {lineNumber: 6, data: '00110101001010010000000000000100'}, 128 | > ], 129 | > }, 130 | > ...{ 131 | > key: 29, 132 | > assembly: '\tj\tlab1', 133 | > binary: [{lineNumber: 22, data: '00001000000100000000000000000110'}], 134 | > }, 135 | > {key: 30, assembly: 'lab5:', binary: []}, 136 | > { 137 | > key: 31, 138 | > assembly: '\tori\t$16, $16, 0xf0f0', 139 | > binary: [{lineNumber: 23, data: '00110110000100001111000011110000'}], 140 | > }, 141 | > ]; 142 | > ``` 143 | 144 | ## simulator 145 | 146 | > function for getting `simulating data` as result or process 147 | 148 | `cycle`: the number of step requested by user for instructions 149 | 150 | `returnCycles`: if user want to get process data, returnCycles should be True. (default : false) 151 | 152 | ```typescript 153 | 154 | export interface simulatorOutputType { 155 | PC: string; 156 | registers: {[key: string]: string}; 157 | dataSection: {[key: string]: string} | Record; 158 | stackSection: {[key: string]: string} | Record; 159 | } 160 | 161 | export interface ISimulatorOutput { 162 | result: simulatorOutputType; 163 | history: simulatorOutputType[] | null; 164 | } 165 | 166 | export function simulator( 167 | assemblyInstructions: string[], 168 | cycleNum: number, 169 | returnHistory = false, 170 | ): Promise { 171 | ... 172 | return returnHistory ? {result, history: CYCLES} : {result, history: null}; 173 | }; 174 | ``` 175 | 176 | > **output (after number of cycle)** 177 | > 178 | > ```js 179 | > { 180 | > PC: '0x00400058', 181 | > registers: { 182 | > R0: '0x00000000', 183 | > R1: '0x00000000', 184 | > R2: '0x00000000', 185 | > R3: '0x0000000a', 186 | > R4: '0x10000000', 187 | > R5: '0x00000000', 188 | > R6: '0x00000000', 189 | > R7: '0x00000000', 190 | > R8: '0x00000000', 191 | > R9: '0x00000000', 192 | > R10: '0x00000000', 193 | > R11: '0x00000000', 194 | > R12: '0x00000000', 195 | > R13: '0x00000000', 196 | > R14: '0x00000000', 197 | > R15: '0x00000000', 198 | > R16: '0x00000000', 199 | > R17: '0x00000000', 200 | > R18: '0x00000000', 201 | > R19: '0x00000000', 202 | > R20: '0x00000000', 203 | > R21: '0x00000000', 204 | > R22: '0x00000000', 205 | > R23: '0x00000000', 206 | > R24: '0x00000000', 207 | > R25: '0x00000000', 208 | > R26: '0x00000000', 209 | > R27: '0x00000000', 210 | > R28: '0x00000000', 211 | > R29: '0x80000000', 212 | > R30: '0x00000000', 213 | > R31: '0x00000000' 214 | > }, 215 | > dataSection: { 216 | > '0x10000000': '0x00000001', 217 | > '0x10000004': '0x0000000a', 218 | > '0x10000008': '0x00000000' 219 | > }, 220 | > stackSection: { 221 | > '0x7ffffff4': '0x0000000a', 222 | > '0x7ffffff8': '0x00000000', 223 | > '0x7ffffffc': '0x00000000' 224 | > } 225 | > } 226 | > ``` 227 | 228 | ## Usage 229 | 230 | ### **Assembly Language → Binary Instruction** 231 | 232 | ```js 233 | // import functions 234 | import { assemble } from "mips-simulator-js"; 235 | 236 | /* 237 | * if the inputFilePath is '/Users/user/simulator/sample_input/sample/example1.s', 238 | * currDirectory : '/Users/user/simulator' 239 | * inputFolderPath : 'sample_input/sample' 240 | * inputFileName: 'example1.s' 241 | */ 242 | const inputFolderName = 'sample_input/sample'; 243 | const inputFileName = 'example1.s'; 244 | /* 245 | * if the outputFilePath is '/Users/user/simulator/sample_input/sample/example1.s', 246 | * currDirectory : '/Users/user/simulator' 247 | * outputFolderPath : 'sample_input/sample' 248 | * outputFileName: 'example1.o' 249 | * content : ['01010', '01010'] 250 | */ 251 | const outputFolderPath = 'sample_input/sample'; 252 | const outputFileName = 'example1.o'; 253 | 254 | const assemblyInstructions = makeInput(inputFolderName, inputFileName); 255 | const { output, mappingDetail } = assemble(assemblyInstructions); 256 | 257 | makeObjectFile(outputFolderPath, outputFileName, output); 258 | ``` 259 | 260 | ### Input/Output 261 | 262 |

263 | 264 | 265 |

266 | 267 | ### **Simulator** 268 | 269 | ```typescript 270 | // import functions 271 | import { simulator } from "mips-simulator-js"; 272 | 273 | const inputFolderName = 'sample_input/sample'; 274 | const inputFileName = 'example1.s'; 275 | 276 | /* 277 | * input : assemblyInstructions: string[], cycle: number, returnCycles: boolean 278 | 279 | * assemblyInstructions is same as assemblyInstructions in assemble function above. 280 | 281 | * cycle is the number of cycles you want to execute. 282 | * Executing one cycle means that executing one instruction. 283 | 284 | * returnCycles determines the type of return. 285 | * If returnCycles = false (default), Returns only the final form of the result. 286 | * If returnCycles = true, Returns an object containing information of all cycles. 287 | 288 | ex) returnCycles = false, you can use this function as below form. 289 | const result = simulator(makeInput('sample_input', 'example1.s'), 10000, false) 290 | 291 | ex) returnCycles = true, you can use this function as below form. 292 | interface SimulatorResult { 293 | output: simulatorOutputType; 294 | cycles: simulatorOutputType[]; 295 | } 296 | */ 297 | 298 | const assemblyInstructions = makeInput(inputFolderName, inputFileName); 299 | 300 | const fetchSimulator = async (fileContent: string[] | null) => { 301 | const output = await simulator(fileContent, 1000, true); 302 | return output; 303 | }; 304 | 305 | const {result, history} = fetchSimulator(assemblyInstructions); 306 | ``` 307 | 308 | ### Input/Output 309 | 310 |

311 | 312 | 313 |

314 | 315 | ## Usage for React/Next 316 | 317 | You can check out the code and example from [**mips-react-example-ts**](https://github.com/mipsSimulatorUNIST/mips-react-examples-ts) 318 | 319 | ### Problem 320 | 321 | If you use this npm package in your `react` or `next` project, problems will occur in the 'fs', 'path', and 'process' parts that load files. 322 | 323 | reactError 324 | 325 | This problem is caused by the webpack version. For details, refer to the [**webpack official documentation**](https://webpack.kr/migrate/5/#upgrade-webpack-4-and-its-pluginsloaders). 326 | 327 | ### Solution 328 | 329 | The solution is to change the webpack configuration to `false` as shown below and import the file using `fetch`. 330 | 331 | 1. Change webpack config and package settings 332 | 333 | ```js 334 | // node_modules/react-scripts/config/webpack.config.json 335 | module.exports = function (webpackEnv) { 336 | // ... 337 | return { 338 | // ... 339 | resolve: { 340 | // ... 341 | // Add This!👇 342 | fallback: { 343 | "fs": false, 344 | "path": false, 345 | "process": false, 346 | }, 347 | // ... 348 | } 349 | } 350 | } 351 | // package.json 352 | { 353 | // ... 354 | "dependencies": {}, 355 | "devDependencies": {}, 356 | 357 | // Add This👇️ 358 | "browser": { 359 | "fs": false, 360 | "os": false, 361 | "path": false 362 | } 363 | } 364 | ``` 365 | 366 | 2. Creating a file calling function using fetch (This function is a replacement for 'makeInput' provided by the library for use in `React` / `Next`.) 367 | 368 | ```js 369 | const fetchFile = async (filePath: string) => { 370 | await fetch(filePath) 371 | .then(response => response.text()) 372 | .then(text => { 373 | // Create a function to use and put it here! 374 | }); 375 | }; 376 | 377 | // Example 378 | 379 | const [fileContent, setFileContent] = useState(''); 380 | const [binaryInstruction, setBinaryInstruction] = useState( 381 | null 382 | ); 383 | 384 | useEffect(() => { 385 | const fetchFile = async (filePath: string) => { 386 | await fetch(filePath) 387 | .then(response => response.text()) 388 | .then(text => { 389 | setFileContent(text.split('\n')); 390 | }); 391 | }; 392 | const filePath = `sample_input/example01.s`; 393 | fetchFile(filePath); 394 | }, [setFileContent]); 395 | 396 | useEffect(() => { 397 | if (fileContent) 398 | setBinaryInstruction(assemble(fileContent).split("\n")); 399 | }, [fileContent]); 400 | 401 | ``` 402 | 403 | ### ⚠️ Caution 404 | 405 | In the browser, unlike in the local environment, only files or documents in the public path can be used, and the default path is automatically designated as public. Therefore, the assembly file to be converted into an object file using assembler must be stored in the `public` folder. 406 | 407 | ## Changes 408 | 409 | ### >= version 2.1.5 410 | 411 | `arrayOutputType` has deleted, `assemble` function only return string[] as output. 412 | 413 | Add data section, text section size, binary value of data segment and PC to the `mapping table`. 414 | 415 | ### >= version 2.1.3 416 | 417 | #### new parameter for assemble `>= version 2.1.1` 418 | 419 | `arrayOutputType` : if you want to get output with string, it should be false (default : true (string array)) 420 | 421 | `mappingDetailRequest`: if you want to get mapping data (which assembly instruction map into specific binary instruction), it should be true (default : false) 422 | 423 | #### parameter naming changes: `>= version 2.1.1` 424 | 425 | - `assemblerFile` => `assemblyInstructions` (in `assemble`, `simulator`) 426 | - `cycle` => `cycleNum` (in `simulator`) 427 | - `returnCycles` => `returnHistory` (in `simulator`) 428 | 429 | #### return type changes: 430 | 431 | `>= version 2.1.3` 432 | 433 | - `ISimulatorOutput` => `Promise` (in `simulator`) 434 | 435 | `>= version 2.1.1` 436 | 437 | - `output` => `{output, mappingDetail}` (in `assemble`) 438 | - `ISimulatorOutput | simulatorOutputType` => `ISimulatorOutput` (in `simulator`) 439 | 440 | ## Supported Instruction 441 | 442 | you can check 443 | [**MIPS Reference**](https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_Green_Sheet.pdf) 444 | å 445 | In this library, we support below instructions 446 | 447 | | Instruction | Format | opcode | funct | 448 | | :---------: | :----: | :----: | :----: | 449 | | SLL | R | 000000 | 000000 | 450 | | SRL | R | 000000 | 000010 | 451 | | JR | R | 000000 | 001000 | 452 | | ADD | R | 000000 | 100000 | 453 | | ADDU | R | 000000 | 100001 | 454 | | AND | R | 000000 | 100100 | 455 | | NOR | R | 000000 | 100111 | 456 | | OR | R | 000000 | 100101 | 457 | | SLT | R | 000000 | 101010 | 458 | | SLTU | R | 000000 | 101011 | 459 | | SUB | R | 000000 | 100010 | 460 | | SUBU | R | 000000 | 100011 | 461 | | LUI | I | 001111 | null | 462 | | BEQ | I | 000100 | null | 463 | | BNE | I | 000101 | null | 464 | | LW | I | 100011 | null | 465 | | LHU | I | 100101 | null | 466 | | SW | I | 101011 | null | 467 | | SH | I | 101001 | null | 468 | | ADDI | I | 001000 | null | 469 | | ADDIU | I | 001001 | null | 470 | | ANDI | I | 001100 | null | 471 | | ORI | I | 001101 | null | 472 | | SLTI | I | 001010 | null | 473 | | SLTIU | I | 001011 | null | 474 | | J | J | 000010 | null | 475 | | JAL | J | 000011 | null | 476 | 477 | ## pseudo Instruction 478 | 479 | #### **la (load address)** 480 | 481 | `la $2, VAR1` 482 | 483 | - `VAR1` is a label in the data section. It should be converted to lui and ori instructions. 484 | - lui $register, upper 16bit address 485 | ori $register, lower 16bit address 486 | If the lower 16bit address is 0x0000, the ori instruction is useless. 487 | 488 | - Case1) load address is 0x1000 0000 489 |
490 | lui $2, 0x1000 491 | 492 | - Case2) load address is 0x1000 0004 493 |
494 | lui $2, 0x1000 495 |
496 | ori $2, $2, 0x0004 497 | 498 | #### **move** 499 | 500 | `move $1, $2` 501 | 502 | It should be converted to add instruction with $0 as a target register(rt). 503 | 504 | ## Contribution 505 | 506 | If you want to contribute to [**mips-simulator-js**](https://www.npmjs.com/package/mips-simulator-js), please come in [**_Git Repository_**](https://github.com/mipsSimulatorUNIST/simulator) and clone! 507 | 508 | We have completed building CI, and test automation is also ready. 509 | 510 | We are using testing library with `jest` 511 | 512 | All work on Mips-simulator-js happens directly on [Github](https://github.com/mipsSimulatorUNIST/simulator). Both core team members and external contributors send pull requests which go through the same review process. 513 | 514 | ### Contribution process 515 | 516 | Thank you for your interest in contributing to Mips-simulator-js. Before you begin writing code, it is important that you share your intention to contribute with the team, based on the type of contribution 517 | 518 | 1. You want to **propose a new feature** and implement it. 519 | - Post about your intended feature in an [issue](https://github.com/mipsSimulatorUNIST/simulator/issues), then implement it. 520 | - We suggest that the branch name that you implement is better to be {type}/{issue number}/{issue name}. ex) feature/118/githubAction, bugfix/120/typo 521 | 522 | 2. You want to **implement a feature or bug-fix** for an outstanding issue. 523 | - Search for your issue in the [Mips-simulator-js issue list](https://github.com/mipsSimulatorUNIST/simulator/issues). 524 | - Pick an issue and comment that you'd like to work on the feature or bug-fix. 525 | - If you need more context on a particular issue, please ask and we shall provide. 526 | 527 | 3. **Open pull request** 528 | - You implement and test your feature or bug-fix, please submit a Pull Request to [https://github.com/mipsSimulatorUNIST/simulator/pulls](https://github.com/mipsSimulatorUNIST/simulator/pulls) with some test case. 529 | - Once a pull request is accepted and CI is passing, there is nothing else you need to do. we will check and merge the PR for you. 530 | 531 | **_Always opening_** to join this project for developing this library. 532 | 533 | ❗️[_ISSUE_ →](https://github.com/mipsSimulatorUNIST/simulator/issues) 534 | 535 | ✅ [_Pull Request_ →](https://github.com/mipsSimulatorUNIST/simulator/pulls) 536 | 537 | ### required environment (global) 538 | 539 | ```bash 540 | $ npm install typescript -g 541 | ``` 542 | 543 | ## License 544 | 545 | Licensed under the MIT License, Copyright © 2023-present MIPS-Simulator-UNIST 546 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-typescript", "@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import {makeBinaryObject, makeBinaryArray} from '@src/simulator/assembler'; 2 | import {initialize, initializeMem} from '@src/utils/constants'; 3 | import { 4 | IMapDetail, 5 | mainProcess, 6 | makeMappingDetail, 7 | simulatorOutputType, 8 | } from '@src/utils/functions'; 9 | 10 | export interface IAssemble { 11 | readonly output: string[]; 12 | readonly mappingDetail: IMapDetail[] | null; 13 | } 14 | 15 | export interface ISimulatorOutput { 16 | readonly result: simulatorOutputType; 17 | history: simulatorOutputType[] | null; 18 | } 19 | 20 | export function assemble( 21 | assemblyInstructions: string[], 22 | mappingDetailRequest = false, 23 | ): IAssemble { 24 | /* 25 | * input : assemblyInstructions: string[] 26 | * Enter the path where the assembly file is located. 27 | 28 | * If the assemlbyFile path is /Users/junghaejune/simulator/sample_input/example1.s 29 | * you can enter path /Users/junghaejune/simulator/sample_input/example1.s into assemblyInstructions. 30 | * If you don't know the path exactly, you can use makeInput function in functions.ts 31 | * Let your current directory is simulator (/Users/junghaejune/simulator). 32 | * Then you only put makeInput("sample_input", "example1.s") into assemblyInstructions 33 | 34 | * output: string[] 35 | * The assembly file is converted to a string in binary form. 36 | 37 | ex) 38 | input: sample_input/example1.s 39 | ... 40 | main: 41 | and $17, $17, $0 42 | and $18, $18, $0 43 | ... 44 | 45 | output: 46 | [00000010001000001000100000100100, 47 | ... 48 | 00000010010000001001000000100100] 49 | 50 | */ 51 | 52 | const { 53 | dataSectionSize, 54 | textSectionSize, 55 | binaryText, 56 | binaryData, 57 | mappingTable, 58 | dataSeg, 59 | textSeg, 60 | } = makeBinaryObject(assemblyInstructions); 61 | 62 | let mappingDetail: IMapDetail[] | null = null; 63 | 64 | const output: string[] = makeBinaryArray( 65 | dataSectionSize, 66 | textSectionSize, 67 | binaryText, 68 | binaryData, 69 | ); 70 | 71 | if (mappingDetailRequest) { 72 | mappingDetail = makeMappingDetail( 73 | assemblyInstructions, 74 | dataSeg, 75 | textSeg, 76 | mappingTable, 77 | output, 78 | ); 79 | } 80 | 81 | return {output, mappingDetail}; 82 | } 83 | 84 | export async function simulator( 85 | assemblyInstructions: string[], 86 | cycleNum: number, 87 | returnHistory = false, 88 | ): Promise { 89 | /* 90 | * input : assemblyInstructions: string[], cycle: number, returnCycles: boolean 91 | * assemblyInstructions is same as assemblyInstructions in assemble function above. 92 | * cycle is the number of cycles you want to execute. 93 | * Executing one cycle means that executing one instruction. 94 | * returnCycles determines the type of return. 95 | * If returnCycles = false (default), Returns only the final form of the result. 96 | * If returnCycles = true, Returns an object containing information of all cycles. 97 | 98 | ex) returnCycles = false, you can use this function as below form. 99 | const result = simulator(makeInput('sample_input', 'example1.s'), 10000, false) 100 | 101 | ex) returnCycles = true, you can use this function as below form. 102 | interface SimulatorResult { 103 | output: simulatorOutputType; 104 | cycles: simulatorOutputType[]; 105 | } 106 | 107 | const result = simulator( 108 | makeInput('sample_input', 'example1.s'), 109 | 10000, 110 | true, 111 | ) as SimulatorResult; 112 | 113 | * output : The object of Register File. 114 | 115 | ex) 116 | [ 117 | { 118 | PC: '0x00400000', 119 | registers: { 120 | R0: '0x00000000', 121 | R1: '0x00000000', 122 | ... 123 | R31: '0x00000000' 124 | }, 125 | dataSection: { 126 | '0x10000000': '0x00000064', 127 | ... 128 | }, 129 | stackSection: {} 130 | } 131 | ] 132 | */ 133 | const {dataSectionSize, textSectionSize, binaryText, binaryData} = 134 | makeBinaryObject(assemblyInstructions); 135 | 136 | initializeMem(); 137 | 138 | const CYCLES: simulatorOutputType[] = new Array(); 139 | const INST_INFO = initialize( 140 | binaryText.concat(binaryData), 141 | textSectionSize, 142 | dataSectionSize, 143 | ); 144 | 145 | const result = await mainProcess(INST_INFO, cycleNum, CYCLES); 146 | 147 | return new Promise((resolve, reject) => { 148 | try { 149 | const output: ISimulatorOutput = {result, history: null}; 150 | if (returnHistory) output.history = CYCLES; 151 | resolve(output); 152 | } catch (error) { 153 | reject(error); 154 | } 155 | }); 156 | } 157 | -------------------------------------------------------------------------------- /jest.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "clearMocks": true, 3 | "verbose": true, 4 | "collectCoverage": true, 5 | "modulePathIgnorePatterns": ["dist"], 6 | "moduleNameMapper": { 7 | "@root(.*)$": "/$1", 8 | "@src(.*)$": "/src$1", 9 | "@utils(.*)$": "/src/utils$1", 10 | "@simulator(.*)$": "/src/simulator$1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mips-simulator-js", 3 | "version": "2.1.11", 4 | "description": "MIPS Simulator npm package", 5 | "main": "./dist/index.js", 6 | "module": "./dist/index.js", 7 | "types": "./dist/index.d.js", 8 | "scripts": { 9 | "build": "rm -rf ./dist/ && tsc", 10 | "lint": "./node_modules/.bin/eslint .", 11 | "test": "jest", 12 | "pre-test": "npm run build && npm run lint && npm run test", 13 | "publish-npm": "npm run pre-test && npm publish" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/mipsSimulatorUNIST/simulator.git" 18 | }, 19 | "author": "mipsSimulatorUNIST", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/mipsSimulatorUNIST/simulator/issues" 23 | }, 24 | "homepage": "https://github.com/mipsSimulatorUNIST/simulator#readme", 25 | "keywords": [ 26 | "simulator", 27 | "mips", 28 | "assembler" 29 | ], 30 | "devDependencies": { 31 | "@babel/preset-env": "^7.20.2", 32 | "@babel/preset-typescript": "^7.18.6", 33 | "@types/jest": "^29.2.5", 34 | "@types/node": "^18.11.18", 35 | "@typescript-eslint/eslint-plugin": "^5.52.0", 36 | "@typescript-eslint/parser": "^5.52.0", 37 | "babel-jest": "^29.3.1", 38 | "eslint": "^8.31.0", 39 | "eslint-config-prettier": "^8.6.0", 40 | "eslint-import-resolver-typescript": "^3.5.3", 41 | "eslint-plugin-import": "^2.27.5", 42 | "eslint-plugin-prettier": "^4.2.1", 43 | "jest": "^29.3.1", 44 | "prettier": "^2.8.2", 45 | "tsc-alias": "^1.8.2", 46 | "typescript": "^4.9.4" 47 | }, 48 | "dependencies": { 49 | "ts-node": "^10.9.1" 50 | }, 51 | "browser": { 52 | "fs": false, 53 | "path": false, 54 | "process": false 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sample_input/example01.o: -------------------------------------------------------------------------------- 1 | 000000000000000000000000010110000000000000000000000000000000110000000010001000001000100000100100000000100100000010010000001001000011110000001000000100000000000000111100000010010001000000000000001101010010100100000000000001000000000101000000010100000010010000000001011000000101100000100100001000100011000100000000000000010010000101101011000000000000000100000001001000000100100000100101000101010110100011111111111111000010001001010010000000000000001000100001011010110000000000000001000000000001000110010000010000000000000000010010100010000100001000000010001100101001100000100100000101010110100111111111111110100000000010111111001010000010000000000010001100101000000000100111000100010100100000000000000000010000100000010000000000000000011000110110000100001111000011110000000000000000000000000000011001000000000000000000000000001100100000010010001101000101011001111000 -------------------------------------------------------------------------------- /sample_input/example1.s: -------------------------------------------------------------------------------- 1 | .data 2 | data1: .word 100 3 | data2: .word 200 4 | data3: .word 0x12345678 5 | .text 6 | main: 7 | and $17, $17, $0 8 | and $18, $18, $0 9 | la $8, data1 10 | la $9, data2 11 | and $10, $10, $0 12 | lab1: 13 | and $11, $11, $0 14 | lab2: 15 | addi $17, $17, 0x1 16 | addi $11, $11, 0x1 17 | or $9, $9, $0 18 | bne $11, $8, lab2 19 | lab3: 20 | addi $18, $18, 0x2 21 | addi $11, $11, 1 22 | sll $18, $17, 1 23 | srl $17, $18, 1 24 | and $19, $17, $18 25 | bne $11, $9, lab3 26 | lab4: 27 | add $5, $5, $31 28 | nor $16, $17, $18 29 | beq $10, $8, lab5 30 | j lab1 31 | lab5: 32 | ori $16, $16, 0xf0f0 -------------------------------------------------------------------------------- /sample_input/example2.s: -------------------------------------------------------------------------------- 1 | .data 2 | array: .word 3 3 | .word 123 4 | .word 4346 5 | array2: .word 0x11111111 6 | .text 7 | main: 8 | addiu $2, $0, 1024 9 | addu $3, $2, $2 10 | or $4, $3, $2 11 | sll $6, $5, 16 12 | addiu $7, $6, 9999 13 | subu $8, $7, $2 14 | nor $9, $4, $3 15 | ori $10, $2, 255 16 | srl $11, $6, 5 17 | la $4, array2 18 | and $13, $11, $5 19 | andi $14, $4, 100 20 | lui $17, 100 21 | addiu $2, $0, 0xa -------------------------------------------------------------------------------- /sample_input/example3.s: -------------------------------------------------------------------------------- 1 | .data 2 | data1: .word 100 3 | data2: .word 200 4 | data3: .word 0x12345678 5 | .word 0x12341 6 | .text 7 | main: 8 | lui $3, 0x1000 9 | lhu $5, 0($3) 10 | lhu $8, 4($3) 11 | lw $9, 8($3) 12 | lw $10, 12($3) 13 | addiu $5, $5, 24 14 | addiu $6, $0, 124 15 | addu $7, $5, $6 16 | sh $5, 16($3) 17 | sh $6, 20($3) 18 | sh $7, 24($3) 19 | addiu $3, $3, 12 20 | lw $12, -4($3) 21 | lhu $13, -8($3) 22 | lhu $14, -12($3) -------------------------------------------------------------------------------- /sample_input/example4.s: -------------------------------------------------------------------------------- 1 | .data 2 | .text 3 | main: 4 | addu $2, $4, $5 5 | addu $2, $6, $7 6 | subu $9, $3, $2 7 | lab1: 8 | and $11, $11, $0 9 | addiu $10, $10, 0x1 10 | or $6, $6, $0 11 | jal lab3 12 | lab3: 13 | sll $7, $6, 2 14 | srl $5, $4, 2 15 | sltiu $9, $10, 100 16 | beq $9, $0, lab4 17 | jr $31 18 | lab4: 19 | sltu $4, $2, $3 20 | bne $4, $0, lab5 21 | j lab1 22 | lab5: 23 | ori $16, $16, 0xf0f0 -------------------------------------------------------------------------------- /sample_input/example5.s: -------------------------------------------------------------------------------- 1 | .data 2 | data1: .word 0x12c 3 | data2: .word 0xc8 4 | .text 5 | main: 6 | and $10, $10, $0 7 | and $11, $11, $0 8 | la $8, data1 9 | la $9, data2 10 | addiu $10, $10, 0x1 11 | sll $10, $10, 1 12 | sll $11, $11, 1 13 | loop: 14 | addiu $10, $10, 0x1 15 | addiu $11, $11, 1 16 | or $9, $9, $0 17 | subu $18, $18, $10 18 | sll $18, $17, 1 19 | sll $17, $18, 1 20 | addu $11, $11, $31 21 | nor $16, $17, $18 22 | bne $11, $8, loop 23 | j exit 24 | exit: 25 | andi $15, $15, 0x0f -------------------------------------------------------------------------------- /sample_input/example6.s: -------------------------------------------------------------------------------- 1 | .data 2 | sum: .word 0x1000000 3 | data1: .word 0x10 4 | data2: .word 0x100 5 | iter: .word 0x1 6 | .text 7 | main: 8 | addiu $29, $29, -8 9 | sw $30, 4($29) 10 | addu $30, $29, $0 11 | j loop1 12 | loop3: 13 | la $2, sum 14 | slti $2, $2, 3 15 | bne $2, $0, loop2 16 | la $2, sum 17 | srl $3, $2, 1 18 | sw $2, 0($2) 19 | loop2: 20 | la $2, iter 21 | addiu $3, $2, 1 22 | sw $3, 0($2) 23 | loop1: 24 | la $2, iter 25 | addi $28, $0, 10 26 | slt $2, $2, $28 27 | bne $2, $0, loop3 28 | addu $2, $2, $0 29 | move $29, $30 30 | lw $30, 4($29) 31 | addiu $29, $29, 8 -------------------------------------------------------------------------------- /sample_input/example7.s: -------------------------------------------------------------------------------- 1 | .data 2 | data1: .word 1 3 | data2: .word 10 4 | .text 5 | main: 6 | addiu $29, $29, -24 7 | sw $30, 20($29) 8 | addu $30, $29, $0 9 | sw $0, 8($30) 10 | loop1: 11 | lw $2, 8($30) 12 | sltiu $2, $2, 20 13 | beq $2, $0, loop2 14 | lui $4, 0x1000 15 | lw $2, 0($4) 16 | sw $2, 12($30) 17 | lw $3, 4($4) 18 | sw $3, 0($4) 19 | lw $3, 12($30) 20 | sw $3, 4($4) 21 | lw $2, 8($30) 22 | addiu $2, $2, 1 23 | sw $2, 8($30) 24 | j loop1 25 | loop2: 26 | addu $2, $2, $0 27 | addu $29, $30, $0 28 | lw $30, 20($29) 29 | addiu $29, $29, 24 -------------------------------------------------------------------------------- /sample_output/example1.o: -------------------------------------------------------------------------------- 1 | 00000000000000000000000001011000 2 | 00000000000000000000000000001100 3 | 00000010001000001000100000100100 4 | 00000010010000001001000000100100 5 | 00111100000010000001000000000000 6 | 00111100000010010001000000000000 7 | 00110101001010010000000000000100 8 | 00000001010000000101000000100100 9 | 00000001011000000101100000100100 10 | 00100010001100010000000000000001 11 | 00100001011010110000000000000001 12 | 00000001001000000100100000100101 13 | 00010101011010001111111111111100 14 | 00100010010100100000000000000010 15 | 00100001011010110000000000000001 16 | 00000000000100011001000001000000 17 | 00000000000100101000100001000010 18 | 00000010001100101001100000100100 19 | 00010101011010011111111111111010 20 | 00000000101111110010100000100000 21 | 00000010001100101000000000100111 22 | 00010001010010000000000000000001 23 | 00001000000100000000000000000110 24 | 00110110000100001111000011110000 25 | 00000000000000000000000001100100 26 | 00000000000000000000000011001000 27 | 00010010001101000101011001111000 28 | -------------------------------------------------------------------------------- /sample_output/example2.o: -------------------------------------------------------------------------------- 1 | 00000000000000000000000000111100 2 | 00000000000000000000000000010000 3 | 00100100000000100000010000000000 4 | 00000000010000100001100000100001 5 | 00000000011000100010000000100101 6 | 00000000000001010011010000000000 7 | 00100100110001110010011100001111 8 | 00000000111000100100000000100011 9 | 00000000100000110100100000100111 10 | 00110100010010100000000011111111 11 | 00000000000001100101100101000010 12 | 00111100000001000001000000000000 13 | 00110100100001000000000000001100 14 | 00000001011001010110100000100100 15 | 00110000100011100000000001100100 16 | 00111100000100010000000001100100 17 | 00100100000000100000000000001010 18 | 00000000000000000000000000000011 19 | 00000000000000000000000001111011 20 | 00000000000000000001000011111010 21 | 00010001000100010001000100010001 22 | -------------------------------------------------------------------------------- /sample_output/example3.o: -------------------------------------------------------------------------------- 1 | 00000000000000000000000000111100 2 | 00000000000000000000000000010000 3 | 00111100000000110001000000000000 4 | 10010100011001010000000000000000 5 | 10010100011010000000000000000100 6 | 10001100011010010000000000001000 7 | 10001100011010100000000000001100 8 | 00100100101001010000000000011000 9 | 00100100000001100000000001111100 10 | 00000000101001100011100000100001 11 | 10100100011001010000000000010000 12 | 10100100011001100000000000010100 13 | 10100100011001110000000000011000 14 | 00100100011000110000000000001100 15 | 10001100011011001111111111111100 16 | 10010100011011011111111111111000 17 | 10010100011011101111111111110100 18 | 00000000000000000000000001100100 19 | 00000000000000000000000011001000 20 | 00010010001101000101011001111000 21 | 00000000000000010010001101000001 22 | -------------------------------------------------------------------------------- /sample_output/example4.o: -------------------------------------------------------------------------------- 1 | 00000000000000000000000001000000 2 | 00000000000000000000000000000000 3 | 00000000100001010001000000100001 4 | 00000000110001110001000000100001 5 | 00000000011000100100100000100011 6 | 00000001011000000101100000100100 7 | 00100101010010100000000000000001 8 | 00000000110000000011000000100101 9 | 00001100000100000000000000000111 10 | 00000000000001100011100010000000 11 | 00000000000001000010100010000010 12 | 00101101010010010000000001100100 13 | 00010001001000000000000000000001 14 | 00000011111000000000000000001000 15 | 00000000010000110010000000101011 16 | 00010100100000000000000000000001 17 | 00001000000100000000000000000011 18 | 00110110000100001111000011110000 19 | -------------------------------------------------------------------------------- /sample_output/example5.o: -------------------------------------------------------------------------------- 1 | 00000000000000000000000001001100 2 | 00000000000000000000000000001000 3 | 00000001010000000101000000100100 4 | 00000001011000000101100000100100 5 | 00111100000010000001000000000000 6 | 00111100000010010001000000000000 7 | 00110101001010010000000000000100 8 | 00100101010010100000000000000001 9 | 00000000000010100101000001000000 10 | 00000000000010110101100001000000 11 | 00100101010010100000000000000001 12 | 00100101011010110000000000000001 13 | 00000001001000000100100000100101 14 | 00000010010010101001000000100011 15 | 00000000000100011001000001000000 16 | 00000000000100101000100001000000 17 | 00000001011111110101100000100001 18 | 00000010001100101000000000100111 19 | 00010101011010001111111111110111 20 | 00001000000100000000000000010010 21 | 00110001111011110000000000001111 22 | 00000000000000000000000100101100 23 | 00000000000000000000000011001000 24 | -------------------------------------------------------------------------------- /sample_output/example6.o: -------------------------------------------------------------------------------- 1 | 00000000000000000000000001011100 2 | 00000000000000000000000000010000 3 | 00100111101111011111111111111000 4 | 10101111101111100000000000000100 5 | 00000011101000001111000000100001 6 | 00001000000100000000000000001110 7 | 00111100000000100001000000000000 8 | 00101000010000100000000000000011 9 | 00010100010000000000000000000011 10 | 00111100000000100001000000000000 11 | 00000000000000100001100001000010 12 | 10101100010000100000000000000000 13 | 00111100000000100001000000000000 14 | 00110100010000100000000000001100 15 | 00100100010000110000000000000001 16 | 10101100010000110000000000000000 17 | 00111100000000100001000000000000 18 | 00110100010000100000000000001100 19 | 00100000000111000000000000001010 20 | 00000000010111000001000000101010 21 | 00010100010000001111111111110001 22 | 00000000010000000001000000100001 23 | 00000011110000001110100000100000 24 | 10001111101111100000000000000100 25 | 00100111101111010000000000001000 26 | 00000001000000000000000000000000 27 | 00000000000000000000000000010000 28 | 00000000000000000000000100000000 29 | 00000000000000000000000000000001 30 | -------------------------------------------------------------------------------- /sample_output/example7.o: -------------------------------------------------------------------------------- 1 | 00000000000000000000000001011000 2 | 00000000000000000000000000001000 3 | 00100111101111011111111111101000 4 | 10101111101111100000000000010100 5 | 00000011101000001111000000100001 6 | 10101111110000000000000000001000 7 | 10001111110000100000000000001000 8 | 00101100010000100000000000010100 9 | 00010000010000000000000000001011 10 | 00111100000001000001000000000000 11 | 10001100100000100000000000000000 12 | 10101111110000100000000000001100 13 | 10001100100000110000000000000100 14 | 10101100100000110000000000000000 15 | 10001111110000110000000000001100 16 | 10101100100000110000000000000100 17 | 10001111110000100000000000001000 18 | 00100100010000100000000000000001 19 | 10101111110000100000000000001000 20 | 00001000000100000000000000000100 21 | 00000000010000000001000000100001 22 | 00000011110000001110100000100001 23 | 10001111101111100000000000010100 24 | 00100111101111010000000000011000 25 | 00000000000000000000000000000001 26 | 00000000000000000000000000001010 27 | -------------------------------------------------------------------------------- /simulator_sample_output/example01.o: -------------------------------------------------------------------------------- 1 | Program Counter 2 | PC: 0x00400020 3 | 4 | Registers 5 | R0: 0x00000000 6 | R1: 0x00000000 7 | R2: 0x00000000 8 | R3: 0x00000000 9 | R4: 0x00000000 10 | R5: 0x00000000 11 | R6: 0x00000000 12 | R7: 0x00000000 13 | R8: 0x10000000 14 | R9: 0x10000004 15 | R10: 0x00000000 16 | R11: 0x000009c2 17 | R12: 0x00000000 18 | R13: 0x00000000 19 | R14: 0x00000000 20 | R15: 0x00000000 21 | R16: 0x00000000 22 | R17: 0x000009c3 23 | R18: 0x00000000 24 | R19: 0x00000000 25 | R20: 0x00000000 26 | R21: 0x00000000 27 | R22: 0x00000000 28 | R23: 0x00000000 29 | R24: 0x00000000 30 | R25: 0x00000000 31 | R26: 0x00000000 32 | R27: 0x00000000 33 | R28: 0x00000000 34 | R29: 0x80000000 35 | R30: 0x00000000 36 | R31: 0x00000000 37 | 38 | Data section 39 | 0x10000000: 0x00000064 40 | 0x10000004: 0x000000c8 41 | 0x10000008: 0x12345678 42 | 0x1000000c: 0x00000000 43 | 44 | 45 | -------------------------------------------------------------------------------- /simulator_sample_output/example02.o: -------------------------------------------------------------------------------- 1 | Program Counter 2 | PC: 0x0040003c 3 | 4 | Registers 5 | R0: 0x00000000 6 | R1: 0x00000000 7 | R2: 0x0000000a 8 | R3: 0x00000800 9 | R4: 0x1000000c 10 | R5: 0x00000000 11 | R6: 0x00000000 12 | R7: 0x0000270f 13 | R8: 0x0000230f 14 | R9: 0xfffff3ff 15 | R10: 0x000004ff 16 | R11: 0x00000000 17 | R12: 0x00000000 18 | R13: 0x00000000 19 | R14: 0x00000004 20 | R15: 0x00000000 21 | R16: 0x00000000 22 | R17: 0x00640000 23 | R18: 0x00000000 24 | R19: 0x00000000 25 | R20: 0x00000000 26 | R21: 0x00000000 27 | R22: 0x00000000 28 | R23: 0x00000000 29 | R24: 0x00000000 30 | R25: 0x00000000 31 | R26: 0x00000000 32 | R27: 0x00000000 33 | R28: 0x00000000 34 | R29: 0x80000000 35 | R30: 0x00000000 36 | R31: 0x00000000 37 | 38 | Data section 39 | 0x10000000: 0x00000003 40 | 0x10000004: 0x0000007b 41 | 0x10000008: 0x000010fa 42 | 0x1000000c: 0x11111111 43 | 0x10000010: 0x00000000 44 | 45 | 46 | -------------------------------------------------------------------------------- /simulator_sample_output/example03.o: -------------------------------------------------------------------------------- 1 | Program Counter 2 | PC: 0x0040003c 3 | 4 | Registers 5 | R0: 0x00000000 6 | R1: 0x00000000 7 | R2: 0x00000000 8 | R3: 0x1000000c 9 | R4: 0x00000000 10 | R5: 0x0000007c 11 | R6: 0x0000007c 12 | R7: 0x000000f8 13 | R8: 0x000000c8 14 | R9: 0x12345678 15 | R10: 0x00012341 16 | R11: 0x00000000 17 | R12: 0x12345678 18 | R13: 0x000000c8 19 | R14: 0x00000064 20 | R15: 0x00000000 21 | R16: 0x00000000 22 | R17: 0x00000000 23 | R18: 0x00000000 24 | R19: 0x00000000 25 | R20: 0x00000000 26 | R21: 0x00000000 27 | R22: 0x00000000 28 | R23: 0x00000000 29 | R24: 0x00000000 30 | R25: 0x00000000 31 | R26: 0x00000000 32 | R27: 0x00000000 33 | R28: 0x00000000 34 | R29: 0x80000000 35 | R30: 0x00000000 36 | R31: 0x00000000 37 | 38 | Data section 39 | 0x10000000: 0x00000064 40 | 0x10000004: 0x000000c8 41 | 0x10000008: 0x12345678 42 | 0x1000000c: 0x00012341 43 | 0x10000010: 0x0000007c 44 | 0x10000014: 0x0000007c 45 | 0x10000018: 0x000000f8 46 | 47 | 48 | -------------------------------------------------------------------------------- /simulator_sample_output/example04.o: -------------------------------------------------------------------------------- 1 | Program Counter 2 | PC: 0x00400020 3 | 4 | Registers 5 | R0: 0x00000000 6 | R1: 0x00000000 7 | R2: 0x00000000 8 | R3: 0x00000000 9 | R4: 0x00000000 10 | R5: 0x00000000 11 | R6: 0x00000000 12 | R7: 0x00000000 13 | R8: 0x00000000 14 | R9: 0x00000001 15 | R10: 0x00000001 16 | R11: 0x00000000 17 | R12: 0x00000000 18 | R13: 0x00000000 19 | R14: 0x00000000 20 | R15: 0x00000000 21 | R16: 0x00000000 22 | R17: 0x00000000 23 | R18: 0x00000000 24 | R19: 0x00000000 25 | R20: 0x00000000 26 | R21: 0x00000000 27 | R22: 0x00000000 28 | R23: 0x00000000 29 | R24: 0x00000000 30 | R25: 0x00000000 31 | R26: 0x00000000 32 | R27: 0x00000000 33 | R28: 0x00000000 34 | R29: 0x80000000 35 | R30: 0x00000000 36 | R31: 0x00400020 37 | 38 | -------------------------------------------------------------------------------- /simulator_sample_output/example05.o: -------------------------------------------------------------------------------- 1 | Program Counter 2 | PC: 0x00400028 3 | 4 | Registers 5 | R0: 0x00000000 6 | R1: 0x00000000 7 | R2: 0x00000000 8 | R3: 0x00000000 9 | R4: 0x00000000 10 | R5: 0x00000000 11 | R6: 0x00000000 12 | R7: 0x00000000 13 | R8: 0x10000000 14 | R9: 0x10000004 15 | R10: 0x00000459 16 | R11: 0x00000457 17 | R12: 0x00000000 18 | R13: 0x00000000 19 | R14: 0x00000000 20 | R15: 0x00000000 21 | R16: 0xffffffff 22 | R17: 0x00000000 23 | R18: 0x00000000 24 | R19: 0x00000000 25 | R20: 0x00000000 26 | R21: 0x00000000 27 | R22: 0x00000000 28 | R23: 0x00000000 29 | R24: 0x00000000 30 | R25: 0x00000000 31 | R26: 0x00000000 32 | R27: 0x00000000 33 | R28: 0x00000000 34 | R29: 0x80000000 35 | R30: 0x00000000 36 | R31: 0x00000000 37 | 38 | Data section 39 | 0x10000000: 0x0000012c 40 | 0x10000004: 0x000000c8 41 | 0x10000008: 0x00000000 42 | 43 | 44 | -------------------------------------------------------------------------------- /simulator_sample_output/example06.o: -------------------------------------------------------------------------------- 1 | Program Counter 2 | PC: 0x0040005c 3 | 4 | Registers 5 | R0: 0x00000000 6 | R1: 0x00000000 7 | R2: 0x00000000 8 | R3: 0x00000000 9 | R4: 0x00000000 10 | R5: 0x00000000 11 | R6: 0x00000000 12 | R7: 0x00000000 13 | R8: 0x00000000 14 | R9: 0x00000000 15 | R10: 0x00000000 16 | R11: 0x00000000 17 | R12: 0x00000000 18 | R13: 0x00000000 19 | R14: 0x00000000 20 | R15: 0x00000000 21 | R16: 0x00000000 22 | R17: 0x00000000 23 | R18: 0x00000000 24 | R19: 0x00000000 25 | R20: 0x00000000 26 | R21: 0x00000000 27 | R22: 0x00000000 28 | R23: 0x00000000 29 | R24: 0x00000000 30 | R25: 0x00000000 31 | R26: 0x00000000 32 | R27: 0x00000000 33 | R28: 0x0000000a 34 | R29: 0x80000000 35 | R30: 0x00000000 36 | R31: 0x00000000 37 | 38 | Data section 39 | 0x10000000: 0x01000000 40 | 0x10000004: 0x00000010 41 | 0x10000008: 0x00000100 42 | 0x1000000c: 0x00000001 43 | 0x10000010: 0x00000000 44 | 45 | 46 | Stack section 47 | 0x7ffffffc: 0x00000000 48 | 49 | 50 | -------------------------------------------------------------------------------- /simulator_sample_output/example07.o: -------------------------------------------------------------------------------- 1 | Program Counter 2 | PC: 0x00400058 3 | 4 | Registers 5 | R0: 0x00000000 6 | R1: 0x00000000 7 | R2: 0x00000000 8 | R3: 0x0000000a 9 | R4: 0x10000000 10 | R5: 0x00000000 11 | R6: 0x00000000 12 | R7: 0x00000000 13 | R8: 0x00000000 14 | R9: 0x00000000 15 | R10: 0x00000000 16 | R11: 0x00000000 17 | R12: 0x00000000 18 | R13: 0x00000000 19 | R14: 0x00000000 20 | R15: 0x00000000 21 | R16: 0x00000000 22 | R17: 0x00000000 23 | R18: 0x00000000 24 | R19: 0x00000000 25 | R20: 0x00000000 26 | R21: 0x00000000 27 | R22: 0x00000000 28 | R23: 0x00000000 29 | R24: 0x00000000 30 | R25: 0x00000000 31 | R26: 0x00000000 32 | R27: 0x00000000 33 | R28: 0x00000000 34 | R29: 0x80000000 35 | R30: 0x00000000 36 | R31: 0x00000000 37 | 38 | Data section 39 | 0x10000000: 0x00000001 40 | 0x10000004: 0x0000000a 41 | 0x10000008: 0x00000000 42 | 43 | 44 | Stack section 45 | 0x7ffffff4: 0x0000000a 46 | 0x7ffffff8: 0x00000000 47 | 0x7ffffffc: 0x00000000 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/simulator/assembler.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BYTES_PER_WORD, 3 | instT, 4 | instList, 5 | MEM_DATA_START, 6 | MEM_TEXT_START, 7 | section, 8 | symbolT, 9 | SYMBOL_TABLE, 10 | resetSymbolTable, 11 | } from '@utils/constants'; 12 | import {numToBits, symbolTableAddEntry, toHexAndPad} from '@utils/functions'; 13 | 14 | export const makeSymbolTable = (inputs: string[]) => { 15 | /* 16 | * make symbol table from assembly file 17 | * using SYMBOL_TABLE in constants.ts 18 | * 19 | * 'dataSeg'에 data 저장 20 | * 'textSeg'에 text 저장 21 | * 22 | * .text 23 | * - indicates that following items are stored in the user text segment, typically instructions 24 | * - It always starts from 0x400000 (MEM_TEXT_START) 25 | 26 | * .data 27 | * - indicates that following data items are stored in the data segment 28 | * - It always starts from 0x10000000 (MEM_DATA_START) 29 | * 30 | * return 31 | * { 32 | * dataSeg : dataSeg, 33 | * textSeg : textSeg, 34 | * dataSectionSize : dataSectionSize, 35 | * textSectionSize : textSectionSize 36 | * } 37 | * 38 | * [USAGE EXAMPLE] 39 | * const {dataSeg, textSeg, dataSectionSize, textSectionSize} = makeSymbolTable(inputs); 40 | */ 41 | resetSymbolTable(); 42 | let address = 0; 43 | let curSection = section.MAX_SIZE; 44 | 45 | let dataSectionSize = 0; 46 | let textSectionSize = 0; 47 | 48 | const dataSeg: string[] = []; 49 | const textSeg: string[] = []; 50 | 51 | inputs.forEach((input: string) => { 52 | const splited: string[] = input.split('\t').filter(s => s !== ''); // ex. ['array:', '.word', '3'] 53 | const symbol: symbolT = new symbolT(); 54 | 55 | if (splited[0] == '.data') { 56 | curSection = section.DATA; 57 | address = MEM_DATA_START; 58 | return; 59 | } else if (splited[0] == '.text') { 60 | curSection = section.TEXT; 61 | address = MEM_TEXT_START; 62 | return; 63 | } else if (curSection === section.DATA) { 64 | if (splited.length === 2) { 65 | // ex. ['.word','123'] 66 | dataSeg.push(splited[1]); 67 | } else { 68 | // ex. ['array:', '.word', '3'] 69 | symbol.address = address; 70 | symbol.name = splited[0].replace(':', ''); 71 | symbolTableAddEntry(symbol); 72 | dataSeg.push(splited[2]); 73 | } 74 | 75 | dataSectionSize += BYTES_PER_WORD; 76 | } else if (curSection === section.TEXT) { 77 | if (splited.length === 1) { 78 | // ex. ['main:'] 79 | symbol.name = splited[0].replace(':', ''); 80 | symbol.address = address; 81 | symbolTableAddEntry(symbol); 82 | return; 83 | } else { 84 | // ex. ['and', '$17, $17, $0'] 85 | const name: string = splited[0]; 86 | textSeg.push(input); // ex. 'and $17, $17, $0' 87 | 88 | if (name === 'la') { 89 | const targetSymbol: string = splited[1].split(' ')[1]; // ex. 'data1' 90 | const targetAddress: string = toHexAndPad(SYMBOL_TABLE[targetSymbol]); 91 | if (targetAddress.slice(4) !== '0000') { 92 | textSectionSize += BYTES_PER_WORD; 93 | address += BYTES_PER_WORD; 94 | } 95 | } 96 | } 97 | textSectionSize += BYTES_PER_WORD; 98 | } 99 | 100 | address += BYTES_PER_WORD; 101 | }); 102 | 103 | return {dataSeg, textSeg, dataSectionSize, textSectionSize}; 104 | }; 105 | 106 | export function recordTextSection(textSeg: string[]): [string[], number[][]] { 107 | /* 108 | * parameter로 textSeg를 받는다. 109 | * textSeg 있는 text들 한 줄 씩 체크해서 binaryText 리스트에 바이너리 문장으로 추가 110 | * 명령어 타입별(R, I, J)로 명령어 이름별로 묶어서 번역 111 | * 112 | * binaryText 이라는 list에 명령어를 번역한 binary 문장을 한 줄씩 추가 113 | * return binaryText 114 | * binaryText: ['00000000000000000000000001011000', '00000000000000000000000000001100'] 115 | */ 116 | 117 | let curAddress: number = MEM_TEXT_START; 118 | let instruct: string[]; 119 | let address: number; 120 | let rs: string; 121 | let rt: string; 122 | let rd: string; 123 | let imm: string; 124 | let shamt: string; 125 | let immReg: string; 126 | const binaryText: string[] = []; 127 | const mappingTable: number[][] = []; 128 | 129 | let binaryInstructionCounter = 0; 130 | 131 | textSeg.forEach((text, i) => { 132 | mappingTable.push([]); 133 | instruct = text.slice(1).replace(/ /g, '').split(/,|\t/); 134 | const opName: string = instruct[0]; 135 | 136 | if (opName === 'la') { 137 | address = SYMBOL_TABLE[instruct[2]]; 138 | rt = numToBits(Number(instruct[1].replace('$', '')), 5); 139 | imm = numToBits(parseInt(address.toString(16).slice(0, 4), 16), 16); 140 | binaryText.push('001111' + '00000' + rt + imm); 141 | 142 | if (address.toString(16).slice(4, 8) !== '0000') { 143 | imm = numToBits(parseInt(address.toString(16).slice(4, 8), 16), 16); 144 | binaryText.push('001101' + rt + rt + imm); 145 | curAddress += BYTES_PER_WORD; 146 | 147 | // if two binary instructions are made by la instruction, then it should map 'current assembly instruction' to 'two binary instructions' 148 | mappingTable[i].push(binaryInstructionCounter); 149 | binaryInstructionCounter++; 150 | } 151 | } else if (opName === 'move') { 152 | //op = ADD op "000000" 153 | rs = numToBits(Number(instruct[2].replace('$', '')), 5); 154 | rt = '00000'; 155 | rd = numToBits(Number(instruct[1].replace('$', '')), 5); 156 | shamt = '00000'; 157 | binaryText.push('000000' + rs + rt + rd + shamt + '100000'); //funct = "100000" 158 | } else { 159 | const opInfo: instT = instList[opName]; 160 | if (opInfo.type === 'R') { 161 | if (opInfo.name === 'sll' || opInfo.name === 'srl') { 162 | rs = '00000'; 163 | rt = numToBits(Number(instruct[2].replace('$', '')), 5); 164 | rd = numToBits(Number(instruct[1].replace('$', '')), 5); 165 | shamt = numToBits(Number(instruct[3]), 5); 166 | } else if (opInfo.name === 'jr') { 167 | rs = numToBits(Number(instruct[1].replace('$', '')), 5); 168 | rt = '00000'; 169 | rd = '00000'; 170 | shamt = '00000'; 171 | } else { 172 | rs = numToBits(Number(instruct[2].replace('$', '')), 5); 173 | rt = numToBits(Number(instruct[3].replace('$', '')), 5); 174 | rd = numToBits(Number(instruct[1].replace('$', '')), 5); 175 | shamt = '00000'; 176 | } 177 | binaryText.push(opInfo.op + rs + rt + rd + shamt + opInfo.funct); 178 | } else if (opInfo.type === 'I') { 179 | if (opInfo.name === 'lui') { 180 | rt = numToBits(Number(instruct[1].replace('$', '')), 5); 181 | rs = '00000'; 182 | imm = 183 | instruct[2].slice(0, 2) === '0x' 184 | ? numToBits(parseInt(instruct[2].slice(2), 16), 16) 185 | : numToBits(Number(instruct[2]), 16); 186 | } else if (opInfo.name === 'beq' || opInfo.name === 'bne') { 187 | imm = numToBits( 188 | Number((SYMBOL_TABLE[instruct[3]] - (curAddress + 4)) / 4), 189 | 16, 190 | ); 191 | rs = numToBits(Number(instruct[1].replace('$', '')), 5); 192 | rt = numToBits(Number(instruct[2].replace('$', '')), 5); 193 | } else if ( 194 | opInfo.name === 'lw' || 195 | opInfo.name === 'lhu' || 196 | opInfo.name === 'sw' || 197 | opInfo.name === 'sh' 198 | ) { 199 | immReg = instruct[2].split('(')[1].split(')')[0]; 200 | rs = numToBits(Number(immReg.replace('$', '')), 5); 201 | rt = numToBits(Number(instruct[1].replace('$', '')), 5); 202 | imm = numToBits(Number(instruct[2].split('(')[0]), 16); 203 | } else { 204 | rs = numToBits(Number(instruct[2].replace('$', '')), 5); 205 | rt = numToBits(Number(instruct[1].replace('$', '')), 5); 206 | 207 | imm = 208 | instruct[3].slice(0, 2) === '0x' 209 | ? numToBits(parseInt(instruct[3].slice(2), 16), 16) 210 | : numToBits(Number(instruct[3]), 16); 211 | } 212 | binaryText.push(opInfo.op + rs + rt + imm); 213 | } else if (opInfo.type === 'J') { 214 | address = Number(SYMBOL_TABLE[instruct[1]]) / 4; 215 | binaryText.push(opInfo.op + numToBits(address, 26)); 216 | } 217 | } 218 | curAddress += BYTES_PER_WORD; 219 | 220 | mappingTable[i].push(binaryInstructionCounter); 221 | binaryInstructionCounter++; 222 | }); 223 | 224 | return [binaryText, mappingTable]; 225 | } 226 | 227 | export function recordDataSection(dataSeg: string[]): string[] { 228 | /* 229 | * input값을 dataSeg를 받는다. 230 | * dataSeg에 있는 data들 한 줄 씩 체크해서 binaryData 리스트에 바이너리 문장으로 추가 231 | * data값을 그대로 binary 문자로 번역 232 | * 233 | * binaryData 이라는 list에 명령어를 번역한 binary 문장을 한 줄씩 추가 234 | * return binaryData 235 | * ex) binaryData: ['00000010001000001000100000100100', '00000010010000001001000000100100'] 236 | */ 237 | 238 | let dataNum: number; 239 | const binaryData: string[] = []; 240 | for (const data of dataSeg) { 241 | dataNum = 242 | data.slice(0, 2) === '0x' ? parseInt(data.slice(2), 16) : Number(data); 243 | binaryData.push(numToBits(dataNum)); 244 | } 245 | return binaryData; 246 | } 247 | 248 | export function makeBinaryObject(inputs: string[]) { 249 | const {dataSeg, textSeg, dataSectionSize, textSectionSize} = 250 | makeSymbolTable(inputs); 251 | const [binaryText, mappingTable]: [string[], number[][]] = 252 | recordTextSection(textSeg); 253 | const binaryData: string[] = recordDataSection(dataSeg); 254 | 255 | return { 256 | dataSectionSize, 257 | textSectionSize, 258 | binaryText, 259 | binaryData, 260 | mappingTable, 261 | dataSeg, 262 | textSeg, 263 | }; 264 | } 265 | 266 | export function makeBinaryArray( 267 | dataSectionSize: number, 268 | textSectionSize: number, 269 | binaryText: string[], 270 | binaryData: string[], 271 | ): string[] { 272 | const output: string[] = [ 273 | numToBits(textSectionSize, 32), 274 | numToBits(dataSectionSize, 32), 275 | ...binaryText, 276 | ...binaryData, 277 | ]; 278 | 279 | return output; 280 | } 281 | 282 | export function makeBinaryString( 283 | dataSectionSize: number, 284 | textSectionSize: number, 285 | binaryText: string[], 286 | binaryData: string[], 287 | ): string { 288 | /* 289 | * output에 text 문장 개수를 binary로 번역해서 추가 290 | * output에 data 개수를 binary로 번역해서 추가 291 | * 292 | */ 293 | const binarySize: string[] = [ 294 | numToBits(textSectionSize, 32), 295 | numToBits(dataSectionSize, 32), 296 | ]; 297 | let output = ''; 298 | 299 | binarySize.concat(binaryText, binaryData).map(binaryLine => { 300 | output += `${binaryLine}\n`; 301 | }); 302 | 303 | return output; 304 | } 305 | -------------------------------------------------------------------------------- /src/simulator/run.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BYTES_PER_WORD, 3 | currentState, 4 | changeRunBit, 5 | instruction, 6 | MEM_TEXT_START, 7 | NUM_INST, 8 | } from '@utils/constants'; 9 | import {getInstInfo, memRead, memWrite, memWriteHalf} from '@utils/functions'; 10 | 11 | export function OPCODE(INST: instruction): number { 12 | return INST.opcode; 13 | } 14 | 15 | export function setOPCODE(INST: instruction, VAL: number): void { 16 | INST.opcode = VAL; 17 | } 18 | 19 | export function FUNC(INST: instruction): number { 20 | return INST.funcCode; 21 | } 22 | 23 | export function setFUNC(INST: instruction, VAL: number): void { 24 | INST.funcCode = VAL; 25 | } 26 | 27 | export function RS(INST: instruction): number { 28 | return INST.rs; 29 | } 30 | 31 | export function setRS(INST: instruction, VAL: number): void { 32 | INST.rs = VAL; 33 | } 34 | 35 | export function RT(INST: instruction): number { 36 | return INST.rt; 37 | } 38 | 39 | export function setRT(INST: instruction, VAL: number): void { 40 | INST.rt = VAL; 41 | } 42 | 43 | export function RD(INST: instruction): number { 44 | return INST.rd; 45 | } 46 | 47 | export function setRD(INST: instruction, VAL: number): void { 48 | INST.rd = VAL; 49 | } 50 | 51 | export function SHAMT(INST: instruction): number { 52 | return INST.shamt; 53 | } 54 | 55 | export function setSHAMT(INST: instruction, VAL: number): void { 56 | INST.shamt = VAL; 57 | } 58 | 59 | export function IMM(INST: instruction): number { 60 | return INST.imm; 61 | } 62 | 63 | export function setIMM(INST: instruction, VAL: number): void { 64 | INST.imm = VAL; 65 | } 66 | 67 | export function IOFFSET(INST: instruction): number { 68 | return IMM(INST); 69 | } 70 | 71 | export function TARGET(INST: instruction): number { 72 | return INST.target; 73 | } 74 | 75 | export function setTARGET(INST: instruction, VAL: number): void { 76 | INST.target = VAL; 77 | } 78 | 79 | export function signEX(X: number): number { 80 | if (X & 0x8000) return X | 0xffff0000; 81 | else return X; 82 | } 83 | 84 | export function zeroEX(X: number): number { 85 | return X & 0x0000ffff; 86 | } 87 | 88 | export function jumpINST(TARGET: number): void { 89 | currentState.PC = TARGET; 90 | } 91 | 92 | export function loadINST(LD: number, MASK: number): number { 93 | return LD & MASK; 94 | } 95 | 96 | export function process_instruction() { 97 | /* 98 | * Procedure: process_instruction 99 | * Purpose: Process one instruction 100 | */ 101 | const info: instruction = getInstInfo(currentState.PC); 102 | 103 | // R type 104 | if (OPCODE(info) === 0x0) { 105 | const rs: number = RS(info); 106 | const rt: number = RT(info); 107 | const rd: number = RD(info); 108 | const shamt: number = SHAMT(info); 109 | const funcCode: number = FUNC(info); 110 | 111 | // ADD 112 | if (funcCode === 32) { 113 | currentState.REGS[rd] = currentState.REGS[rs] + currentState.REGS[rt]; 114 | } 115 | // ADDU 116 | else if (funcCode === 33) { 117 | currentState.REGS[rd] = currentState.REGS[rs] + currentState.REGS[rt]; 118 | } 119 | // SUB 120 | else if (funcCode === 34) { 121 | currentState.REGS[rd] = currentState.REGS[rs] - currentState.REGS[rt]; 122 | } 123 | // SUBU 124 | else if (funcCode === 35) { 125 | currentState.REGS[rd] = currentState.REGS[rs] - currentState.REGS[rt]; 126 | } 127 | // AND 128 | else if (funcCode === 36) { 129 | currentState.REGS[rd] = currentState.REGS[rs] & currentState.REGS[rt]; 130 | } 131 | // OR 132 | else if (funcCode === 37) { 133 | currentState.REGS[rd] = currentState.REGS[rs] | currentState.REGS[rt]; 134 | } 135 | // NOR 136 | else if (funcCode === 39) { 137 | currentState.REGS[rd] = ~(currentState.REGS[rs] | currentState.REGS[rt]); 138 | } 139 | // SLT 140 | else if (funcCode === 42) { 141 | if (currentState.REGS[rs] < currentState.REGS[rt]) 142 | currentState.REGS[rd] = 1; 143 | else currentState.REGS[rd] = 0; 144 | } 145 | // SLTU 146 | else if (funcCode === 43) { 147 | if (currentState.REGS[rs] < currentState.REGS[rt]) 148 | currentState.REGS[rd] = 1; 149 | else currentState.REGS[rd] = 0; 150 | } 151 | // SLL 152 | else if (funcCode === 0) { 153 | currentState.REGS[rd] = currentState.REGS[rt] << shamt; 154 | } 155 | // SRL 156 | else if (funcCode === 2) { 157 | currentState.REGS[rd] = currentState.REGS[rt] >> shamt; 158 | } 159 | // JR 160 | else if (funcCode === 8) { 161 | currentState.PC = currentState.REGS[rs]; 162 | } 163 | 164 | if (funcCode !== 8) currentState.PC += BYTES_PER_WORD; 165 | } 166 | // J 167 | else if (OPCODE(info) === 0x2) { 168 | const target: number = TARGET(info) << 2; 169 | jumpINST(target); 170 | } 171 | // JAL 172 | else if (OPCODE(info) === 0x3) { 173 | const target: number = TARGET(info) << 2; 174 | currentState.REGS[31] = currentState.PC + 8; 175 | jumpINST(target); 176 | } 177 | // I type 178 | else { 179 | const rs: number = RS(info); 180 | const rt: number = RT(info); 181 | const imm: number = IMM(info); 182 | const opcode: number = OPCODE(info); 183 | 184 | // ADDI 185 | if (opcode === 0x8) { 186 | currentState.REGS[rt] = currentState.REGS[rs] + signEX(imm); 187 | } 188 | // ADDIU 189 | else if (opcode === 0x9) { 190 | currentState.REGS[rt] = currentState.REGS[rs] + signEX(imm); 191 | } 192 | // ANDI 193 | else if (opcode === 0xc) { 194 | currentState.REGS[rt] = currentState.REGS[rs] & zeroEX(imm); 195 | } 196 | // BEQ 197 | else if (opcode === 0x4) { 198 | if (currentState.REGS[rs] === currentState.REGS[rt]) 199 | currentState.PC += imm * 4; 200 | } 201 | // BNE 202 | else if (opcode === 0x5) { 203 | if (currentState.REGS[rs] !== currentState.REGS[rt]) { 204 | currentState.PC += signEX(imm) * 4; 205 | } 206 | } 207 | // LHU 208 | else if (opcode === 0x25) { 209 | currentState.REGS[rt] = loadINST( 210 | memRead(currentState.REGS[rs] + signEX(IOFFSET(info))), 211 | 0x0000ffff, 212 | ); 213 | } 214 | // LUI 215 | else if (opcode === 0xf) { 216 | currentState.REGS[rt] = imm << 16; 217 | } 218 | // LW 219 | else if (opcode == 0x23) { 220 | currentState.REGS[rt] = memRead( 221 | currentState.REGS[rs] + signEX(IOFFSET(info)), 222 | ); 223 | } 224 | // ORI 225 | else if (opcode === 0xd) { 226 | currentState.REGS[rt] = currentState.REGS[rs] | zeroEX(imm); 227 | } 228 | // SLTI 229 | else if (opcode === 0xa) { 230 | if (currentState.REGS[rs] < signEX(imm)) currentState.REGS[rt] = 1; 231 | else currentState.REGS[rt] = 0; 232 | } 233 | // SLTIU 234 | else if (opcode === 0xb) { 235 | if (currentState.REGS[rs] < signEX(imm)) currentState.REGS[rt] = 1; 236 | else currentState.REGS[rt] = 0; 237 | } 238 | // SH 239 | else if (opcode === 0x29) { 240 | memWriteHalf( 241 | currentState.REGS[rs] + signEX(IOFFSET(info)), 242 | currentState.REGS[rt], 243 | ); 244 | } 245 | // SW 246 | else if (opcode === 0x2b) { 247 | memWrite( 248 | currentState.REGS[rs] + signEX(IOFFSET(info)), 249 | currentState.REGS[rt], 250 | ); 251 | } 252 | 253 | currentState.PC += BYTES_PER_WORD; 254 | } 255 | 256 | if (currentState.PC - MEM_TEXT_START === NUM_INST * 4) { 257 | changeRunBit(); 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/utils/constants.ts: -------------------------------------------------------------------------------- 1 | import { 2 | initMemory, 3 | initInstInfo, 4 | parseData, 5 | parseInstr, 6 | } from '@utils/functions'; 7 | 8 | export interface Iinstruction { 9 | opcode: number; 10 | funcCode: number; 11 | value: number; 12 | target: number; 13 | rs: number; 14 | rt: number; 15 | imm: number; 16 | rd: number; 17 | shamt: number; 18 | encoding: number; 19 | expr: number; 20 | } 21 | 22 | interface IBcolors { 23 | readonly BLUE: string; 24 | readonly YELLOW: string; 25 | readonly GREEN: string; 26 | readonly RED: string; 27 | readonly ENDC: string; 28 | } 29 | 30 | interface ISection { 31 | readonly DATA: number; 32 | readonly TEXT: number; 33 | readonly MAX_SIZE: number; 34 | } 35 | 36 | export interface SymbolTableType { 37 | readonly name: string; 38 | readonly address: number; 39 | } 40 | 41 | export interface IinstList { 42 | readonly [key: string]: instT; 43 | } 44 | 45 | export interface ISYMBOL_TABLE { 46 | [key: string]: number; 47 | } 48 | 49 | export const DEBUG = 0; 50 | export const MAX_SYMBOL_TABLE_SIZE = 1024; 51 | 52 | export const MEM_TEXT_START = 0x00400000; 53 | export const MEM_TEXT_SIZE = 0x00100000; 54 | export const MEM_DATA_START = 0x10000000; 55 | export const MEM_DATA_SIZE = 0x00100000; 56 | export const MEM_STACK_START = 0x80000000; 57 | export const MEM_STACK_SIZE = 0x00100000; 58 | 59 | export const BYTES_PER_WORD = 4; 60 | export const INST_LIST_LEN = 27; 61 | 62 | export const MIPS_REGS = 32; 63 | export const MEM_GROW_UP = 1; 64 | export const MEM_GROW_DOWN = -1; 65 | export const MEM_NREGIONS = 3; 66 | export const DEBUG_SET = 0; 67 | export const MEM_DUMP_SET = 1; 68 | 69 | export let RUN_BIT = 1; 70 | export let INSTRUCTION_COUNT = 0; 71 | 72 | /* 73 | Main memory 74 | memory will be dynamically allocated at initialization 75 | */ 76 | export let memText: memRegionT; 77 | export let memData: memRegionT; 78 | export let memStack: memRegionT; 79 | export let memRegions: memRegionT[]; 80 | export let currentState: cpuState; 81 | export let NUM_INST: number; 82 | 83 | export const INST_INFO: Iinstruction[] = []; 84 | 85 | export const section: ISection = { 86 | DATA: 0, 87 | TEXT: 1, 88 | MAX_SIZE: 2, 89 | }; 90 | 91 | export const bcolors: IBcolors = { 92 | BLUE: '\x1B[34m', 93 | YELLOW: '\x1B[33m', 94 | GREEN: '\x1B[32m', 95 | RED: '\x1B[31m', 96 | ENDC: '\x1B[0m', 97 | }; 98 | 99 | const start = `[${bcolors.BLUE}START${bcolors.ENDC}] `; 100 | const done = `[${bcolors.YELLOW}DONE${bcolors.ENDC}] `; 101 | const success = `[${bcolors.GREEN}SUCCESS${bcolors.ENDC}] `; 102 | const error = `[${bcolors.RED}ERROR${bcolors.ENDC}] `; 103 | 104 | export const pType: string[] = [start, done, success, error]; 105 | // Structure Declaration 106 | export class instT { 107 | name: string; 108 | type: string; 109 | op: string; 110 | funct: string; 111 | 112 | constructor(name: string, op: string, type: string, funct: string) { 113 | this.name = name; 114 | this.op = op; 115 | this.type = type; 116 | this.funct = funct; 117 | } 118 | } 119 | 120 | export class symbolT { 121 | name: string; 122 | address: number; 123 | 124 | constructor() { 125 | this.name = ''; 126 | this.address = 0; 127 | } 128 | } 129 | 130 | export class laStruct { 131 | op: string; 132 | rt: string; 133 | imm: string; 134 | 135 | constructor(op: string, rt: string, imm: string) { 136 | this.op = op; 137 | this.rt = rt; 138 | this.imm = imm; 139 | } 140 | } 141 | 142 | export class cpuState { 143 | PC: number; 144 | REGS: number[]; 145 | 146 | constructor() { 147 | this.PC = 0; 148 | this.REGS = Array.from({length: 32}, () => 0); 149 | this.REGS[29] = MEM_STACK_START; 150 | } 151 | } 152 | 153 | export class instruction { 154 | opcode: number; 155 | funcCode: number; 156 | value: number; 157 | target: number; 158 | rs: number; 159 | rt: number; 160 | imm: number; 161 | rd: number; 162 | shamt: number; 163 | encoding: number; 164 | expr: number; 165 | 166 | constructor() { 167 | this.opcode = 0; 168 | this.funcCode = 0; 169 | this.value = 0; 170 | this.target = 0; 171 | this.rs = 0; 172 | this.rt = 0; 173 | this.imm = 0; 174 | this.rd = 0; 175 | this.shamt = 0; 176 | this.encoding = 0; 177 | this.expr = 0; 178 | } 179 | } 180 | 181 | export function initialize( 182 | binary: string[], 183 | textSize: number, 184 | dataSize: number, 185 | ): Iinstruction[] { 186 | initMemory(); 187 | 188 | // Load program and service routines into mem 189 | let textIndex = 0; 190 | let size = 0; 191 | 192 | NUM_INST = ~~(textSize / 4); 193 | 194 | // initial memory allocation of text segment 195 | for (let i = 0; i < NUM_INST; i++) INST_INFO.push(new instruction()); 196 | initInstInfo(NUM_INST, INST_INFO); 197 | 198 | binary.forEach(buffer => { 199 | if (size < textSize) { 200 | INST_INFO[textIndex] = parseInstr(buffer, size); 201 | textIndex += 1; 202 | } else if (size < textSize + dataSize) { 203 | parseData(buffer, size - textSize); 204 | } 205 | size += 4; 206 | }); 207 | 208 | currentState.PC = MEM_TEXT_START; 209 | 210 | RUN_BIT = 1; 211 | return INST_INFO; 212 | } 213 | /* 214 | All simulated memory will be managed by this class 215 | use the mem_write and mem_read functions to 216 | access/modify the simulated memory 217 | */ 218 | export class memRegionT { 219 | start: number; 220 | size: number; 221 | mem: number[]; 222 | offBound: number; 223 | type: number; 224 | dirty: boolean; 225 | constructor(start: number, size: number, type: number = MEM_GROW_UP) { 226 | this.start = start; 227 | this.size = size; 228 | this.mem = []; 229 | this.offBound = -(size - 4) * type; 230 | this.type = type; 231 | this.dirty = false; 232 | } 233 | } 234 | 235 | // Global Variable Declaration 236 | const SLL = new instT('sll', '000000', 'R', '000000'); 237 | const SRL = new instT('srl', '000000', 'R', '000010'); 238 | const JR = new instT('jr', '000000', 'R', '001000'); 239 | const ADD = new instT('add', '000000', 'R', '100000'); 240 | const ADDU = new instT('addu', '000000', 'R', '100001'); 241 | const AND = new instT('and', '000000', 'R', '100100'); 242 | const NOR = new instT('nor', '000000', 'R', '100111'); 243 | const OR = new instT('or', '000000', 'R', '100101'); 244 | const SLT = new instT('slt', '000000', 'R', '101010'); 245 | const SLTU = new instT('sltu', '000000', 'R', '101011'); 246 | const SUB = new instT('sub', '000000', 'R', '100010'); 247 | const SUBU = new instT('subu', '000000', 'R', '100011'); 248 | const LUI = new instT('lui', '001111', 'I', ''); 249 | const BEQ = new instT('beq', '000100', 'I', ''); 250 | const BNE = new instT('bne', '000101', 'I', ''); 251 | const LW = new instT('lw', '100011', 'I', ''); 252 | const LHU = new instT('lhu', '100101', 'I', ''); 253 | const SW = new instT('sw', '101011', 'I', ''); 254 | const SH = new instT('sh', '101001', 'I', ''); 255 | const ADDI = new instT('addi', '001000', 'I', ''); 256 | const ADDIU = new instT('addiu', '001001', 'I', ''); 257 | const ANDI = new instT('andi', '001100', 'I', ''); 258 | const ORI = new instT('ori', '001101', 'I', ''); 259 | const SLTI = new instT('slti', '001010', 'I', ''); 260 | const SLTIU = new instT('sltiu', '001011', 'I', ''); 261 | const J = new instT('j', '000010', 'J', ''); 262 | const JAL = new instT('jal', '000011', 'J', ''); 263 | 264 | export const instList: IinstList = { 265 | add: ADD, 266 | addi: ADDI, 267 | addiu: ADDIU, 268 | addu: ADDU, 269 | and: AND, 270 | andi: ANDI, 271 | beq: BEQ, 272 | bne: BNE, 273 | j: J, 274 | jal: JAL, 275 | jr: JR, 276 | lhu: LHU, 277 | lui: LUI, 278 | lw: LW, 279 | nor: NOR, 280 | or: OR, 281 | ori: ORI, 282 | slt: SLT, 283 | slti: SLTI, 284 | sltiu: SLTIU, 285 | sltu: SLTU, 286 | sll: SLL, 287 | srl: SRL, 288 | sh: SH, 289 | sw: SW, 290 | sub: SUB, 291 | subu: SUBU, 292 | }; 293 | 294 | // Global symbol table 295 | export const symbolStruct = new symbolT(); 296 | 297 | export let SYMBOL_TABLE: ISYMBOL_TABLE = {}; 298 | 299 | export const resetSymbolTable = () => { 300 | SYMBOL_TABLE = {}; 301 | }; 302 | 303 | export const initializeMem = () => { 304 | INSTRUCTION_COUNT = 0; 305 | RUN_BIT = 1; 306 | memText = new memRegionT(MEM_TEXT_START, MEM_TEXT_SIZE); 307 | memData = new memRegionT(MEM_DATA_START, MEM_DATA_SIZE); 308 | memStack = new memRegionT( 309 | MEM_STACK_START - MEM_STACK_SIZE, 310 | MEM_STACK_SIZE, 311 | MEM_GROW_DOWN, 312 | ); 313 | memRegions = [memText, memData, memStack]; 314 | currentState = new cpuState(); 315 | }; 316 | 317 | /* INSTRUCTION COUNT ADD */ 318 | export const instAddOne = () => { 319 | INSTRUCTION_COUNT += 1; 320 | }; 321 | 322 | export const numInstSub = () => { 323 | NUM_INST -= 1; 324 | }; 325 | 326 | export const changeRunBit = () => { 327 | RUN_BIT = 0; 328 | }; 329 | -------------------------------------------------------------------------------- /src/utils/functions.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as fs from 'fs'; 3 | import {exit} from 'process'; 4 | 5 | import { 6 | process_instruction, 7 | setFUNC, 8 | setIMM, 9 | setOPCODE, 10 | setRD, 11 | setRS, 12 | setRT, 13 | setSHAMT, 14 | setTARGET, 15 | } from '@simulator/run'; 16 | 17 | import { 18 | bcolors, 19 | currentState, 20 | DEBUG, 21 | DEBUG_SET, 22 | INST_INFO, 23 | instAddOne, 24 | instruction, 25 | Iinstruction, 26 | memData, 27 | memStack, 28 | memRegions, 29 | MIPS_REGS, 30 | MEM_GROW_UP, 31 | MEM_DUMP_SET, 32 | MEM_NREGIONS, 33 | MEM_DATA_START, 34 | MEM_TEXT_START, 35 | pType, 36 | RUN_BIT, 37 | SYMBOL_TABLE, 38 | SymbolTableType, 39 | } from '@utils/constants'; 40 | 41 | export interface simulatorOutputType { 42 | readonly PC: string; 43 | readonly registers: {[key: string]: string}; 44 | readonly dataSection: {[key: string]: string} | Record; 45 | readonly stackSection: {[key: string]: string} | Record; 46 | } 47 | 48 | export interface IBinaryData { 49 | readonly lineNumber: number; 50 | readonly data: string; 51 | } 52 | 53 | export interface IMapDetail { 54 | readonly key: number; 55 | readonly assembly: string; 56 | readonly binary: IBinaryData[]; 57 | } 58 | 59 | export function parseInstr(buffer: string, index: number): instruction { 60 | const instr: instruction = new instruction(); 61 | 62 | setOPCODE(instr, fromBinary(buffer.slice(0, 6))); 63 | 64 | // R type 65 | if (instr.opcode === 0x0) { 66 | setRS(instr, fromBinary(buffer.slice(6, 11))); 67 | setRT(instr, fromBinary(buffer.slice(11, 16))); 68 | setRD(instr, fromBinary(buffer.slice(16, 21))); 69 | setSHAMT(instr, fromBinary(buffer.slice(21, 26))); 70 | setFUNC(instr, fromBinary(buffer.slice(26, 32))); 71 | } 72 | 73 | // J type 74 | else if (instr.opcode === 0x2 || instr.opcode === 0x3) { 75 | setTARGET(instr, fromBinary(buffer.slice(6, 32))); 76 | } 77 | 78 | // I type 79 | else { 80 | setRS(instr, fromBinary(buffer.slice(6, 11))); 81 | setRT(instr, fromBinary(buffer.slice(11, 16))); 82 | setIMM(instr, fromBinary(buffer.slice(16, 32))); 83 | } 84 | 85 | memWrite(MEM_TEXT_START + index, fromBinary(buffer)); 86 | return instr; 87 | } 88 | 89 | export function parseData(buffer: string, index: number) { 90 | //[TODO] Implement this function 91 | memWrite(MEM_DATA_START + index, fromBinary(buffer)); 92 | return; 93 | } 94 | 95 | export function printParseResult( 96 | INST_INFO: Iinstruction[], 97 | textSize: number, 98 | dataSize: number, 99 | ) { 100 | console.log('Instruction Information'); 101 | /* 102 | TYPE I 103 | 0x8: (0x001000)ADDI 104 | 0x9: (0x001001)ADDIU 105 | 0xc: (0x001100)ANDI 106 | 0x4: (0x000100)BEQ 107 | 0x5: (0x000101)BNE 108 | 0x25: (0x011001)LHU 109 | 0xf: (0x001111)LUI 110 | 0x23: (0x100011)LW 111 | 0xd: (0x001101)ORI 112 | 0xa: (0x001010)SLTI 113 | 0xb: (0x001011)SLTIU 114 | 0x29: (0x011101)SH 115 | 0x2b: (0x101011)SW 116 | 117 | TYPE R 118 | 0x0: (0x000000)ADD, ADDU, AND, NOR, OR, SLT, SLTU, SLL, SRL, SUB, SUBU if JR 119 | 120 | TYPE J 121 | 0x2: (0x000010)J 122 | 0x3: (0x000011)JAL 123 | */ 124 | 125 | const TypeIList = [ 126 | 0x8, 0x9, 0xc, 0x4, 0x5, 0x25, 0xf, 0x23, 0xd, 0xa, 0xb, 0x29, 0x2b, 127 | ]; 128 | const TypeRList = [0x0]; 129 | const TypeJList = [0x2, 0x3]; 130 | 131 | for (let i = 0; i < textSize / 4; i++) { 132 | console.log(`INST_INFO[${i}].value : 0x${INST_INFO[i].value.toString(16)}`); 133 | console.log(`INST_INFO[${i}].opcode : ${INST_INFO[i].opcode}`); 134 | 135 | if (INST_INFO[i].opcode in TypeIList) { 136 | console.log(`INST_INFO[${i}].rs : ${INST_INFO[i].rs}`); 137 | console.log(`INST_INFO[${i}].rt : ${INST_INFO[i].rt}`); 138 | console.log(`INST_INFO[${i}].imm : ${INST_INFO[i].imm}`); 139 | } else if (INST_INFO[i].opcode in TypeRList) { 140 | console.log(`INST_INFO[${i}].funcCode : ${INST_INFO[i].funcCode}`); 141 | console.log(`INST_INFO[${i}].rs : ${INST_INFO[i].rs}`); 142 | console.log(`INST_INFO[${i}].rt : ${INST_INFO[i].rt}`); 143 | console.log(`INST_INFO[${i}].rd : ${INST_INFO[i].rd}`); 144 | console.log(`INST_INFO[${i}].shamt : ${INST_INFO[i].shamt}`); 145 | } else if (INST_INFO[i].opcode in TypeJList) { 146 | console.log(`INST_INFO[${i}].target : ${INST_INFO[i].target}`); 147 | } else { 148 | console.log('Not available instrution\n'); 149 | } 150 | } 151 | console.log('Memory Dump - Text Segment\n'); 152 | for (let i = 0; i < textSize; i += 4) { 153 | console.log( 154 | `text_seg[${i}] : 0x${memRead(MEM_TEXT_START + i).toString(16)}`, 155 | ); 156 | } 157 | for (let i = 0; i < dataSize; i += 4) { 158 | console.log( 159 | `text_seg[${i}] : 0x${memRead(MEM_DATA_START + i).toString(16)}`, 160 | ); 161 | } 162 | console.log(`Current PC: ${currentState.PC.toString(16)}`); 163 | } 164 | 165 | export function numToBits(num: number, pad = 32): string { 166 | // 10진수 정수를 2진수 bit로 변경해서 return 167 | if (num >= 0) { 168 | return num.toString(2).padStart(pad, '0'); //양수일때 169 | } else { 170 | num = 2 ** pad + num; 171 | return num.toString(2).padStart(pad, '0'); //음수일때; 172 | } 173 | } 174 | 175 | export function toHexAndPad(num: number, pad = 8): string { 176 | /* 177 | * num : Number or String(숫자 형식, 10진법), pad : Number 178 | * input : 18 => output: '00000012' 179 | * Recommend | num을 Number 타입으로 넣을 것 180 | */ 181 | return Number(num).toString(16).padStart(pad, '0'); 182 | } 183 | 184 | export function symbolTableAddEntry(symbol: SymbolTableType) { 185 | SYMBOL_TABLE[symbol.name] = symbol.address; 186 | if (DEBUG) { 187 | log(1, `${symbol.name}: 0x${toHexAndPad(symbol.address)}`); 188 | } 189 | } 190 | 191 | export function log(printType: number, content: string) { 192 | console.log(pType[printType] + content); 193 | } 194 | 195 | export function isEmpty(value: string | null | undefined | object) { 196 | const emptyArray: string[] = ['']; 197 | if ( 198 | value === '' || 199 | value === null || 200 | value === undefined || 201 | (value !== null && 202 | typeof value === 'object' && 203 | !Object.keys(value).length) || 204 | value === emptyArray 205 | ) { 206 | return true; 207 | } else { 208 | return false; 209 | } 210 | } 211 | 212 | // Parsing an assembly file(*.s) into a list 213 | export function makeInput( 214 | inputFolderName: string, 215 | inputFileName: string, 216 | ): string[] { 217 | /* 218 | if the inputFilePath is /Users/junghaejune/simulator/sample_input/sample/example1.s, 219 | currDirectory : /Users/junghaejune/simulator 220 | inputFolderPath : sample_input/sample 221 | inputFileName: example1.s 222 | */ 223 | 224 | const currDirectory: string = process.cwd(); 225 | const inputFilePath: string = path.join( 226 | currDirectory, 227 | inputFolderName, 228 | inputFileName, 229 | ); 230 | 231 | try { 232 | if (fs.existsSync(inputFilePath) === false) throw 'INPUT_PATH_ERROR'; 233 | 234 | const input: string = fs.readFileSync(inputFilePath, 'utf-8'); 235 | 236 | if (isEmpty(input)) throw 'INPUT_EMPTY'; 237 | return input.split('\n'); 238 | } catch (err) { 239 | if (err === 'INPUT_PATH_ERROR') { 240 | log( 241 | 3, 242 | `No input file ${inputFileName} exists. Please check the file name and path.`, 243 | ); 244 | } else if (err === 'INPUT_EMPTY') { 245 | log( 246 | 3, 247 | `input file ${inputFileName} is not opened. Please check the file`, 248 | ); 249 | } else console.error(err); 250 | exit(1); 251 | } 252 | } 253 | 254 | export function simulatorUnitTest( 255 | testCase: simulatorOutputType, 256 | output: simulatorOutputType, 257 | ) { 258 | function printResult( 259 | origin: {[key: string]: string} | Record, 260 | compare: {[key: string]: string} | Record, 261 | ) { 262 | Object.keys(origin).map(key => { 263 | if (compare[key]) { 264 | const color = 265 | origin[key] === compare[key] ? bcolors.GREEN : bcolors.RED; 266 | console.log( 267 | `${color}${key} : ${origin[key]} ${key} : ${compare[key]}${bcolors.ENDC}`, 268 | ); 269 | } else { 270 | console.log(`${bcolors.RED}${key} : ${origin[key]}${bcolors.ENDC}`); 271 | } 272 | }); 273 | } 274 | 275 | type keyType = 'registers' | 'dataSection' | 'stackSection'; 276 | const keyList: keyType[] = ['registers', 'dataSection', 'stackSection']; 277 | 278 | console.log(`---------------PC---------------`); 279 | console.log( 280 | `${testCase.PC === output.PC ? bcolors.GREEN : bcolors.RED}PC : ${ 281 | testCase.PC 282 | } PC : ${output.PC}${bcolors.ENDC}\n`, 283 | ); 284 | 285 | keyList.map(key => { 286 | console.log(`---------------${key}---------------`); 287 | printResult(testCase[key], output[key]); 288 | console.log('\n'); 289 | }); 290 | } 291 | 292 | export function parseSimulatorOutput(rawOutput: string): simulatorOutputType { 293 | //input : test simulator input 294 | //ouput : object type -> { register : {PC:, R0:,...}, dataSection:{}, stackSection{}} 295 | 296 | function splitHelper(input: string): [string, string] { 297 | const returnValue = input.split(/:|\n/); 298 | return returnValue.length === 2 299 | ? [returnValue[0], returnValue[1].trim()] 300 | : null; 301 | } 302 | 303 | function setTypeParser( 304 | input: string, 305 | ): {[key: string]: string} | Record { 306 | const returnSet = {}; 307 | input 308 | .split(/\n/) 309 | .filter(e => e !== '') 310 | .map(element => { 311 | const result = splitHelper(element); 312 | result ? (returnSet[result[0]] = result[1]) : null; 313 | }); 314 | 315 | return returnSet; 316 | } 317 | 318 | const outputList = rawOutput 319 | .split(/Program Counter\n|Registers\n|Data section|Stack section\n/) 320 | .filter(e => e !== ''); 321 | 322 | const PC = setTypeParser(outputList[0]); 323 | const registers = setTypeParser(outputList[1]); 324 | const dataSection = setTypeParser(outputList[2] || ''); 325 | const stackSection = setTypeParser(outputList[3] || ''); 326 | 327 | return {PC: PC.PC, registers, dataSection, stackSection}; 328 | } 329 | 330 | export function makeOutput( 331 | inputFolderName: string, 332 | inputFileName: string, 333 | ): string { 334 | /* 335 | if the inputFilePath is /Users/junghaejune/simulator/sample_input/sample/example1.s, 336 | currDirectory : /Users/junghaejune/simulator 337 | inputFolderPath : sample_input/sample 338 | inputFileName: example1.s 339 | */ 340 | 341 | const currDirectory: string = process.cwd(); 342 | const inputFilePath: string = path.join( 343 | currDirectory, 344 | inputFolderName, 345 | inputFileName, 346 | ); 347 | 348 | try { 349 | if (fs.existsSync(inputFilePath) === false) throw 'INPUT_PATH_ERROR'; 350 | 351 | const input: string = fs.readFileSync(inputFilePath, 'utf-8'); 352 | 353 | if (isEmpty(input)) throw 'INPUT_EMPTY'; 354 | return input; 355 | } catch (err) { 356 | if (err === 'INPUT_PATH_ERROR') { 357 | log( 358 | 3, 359 | `No input file ${inputFileName} exists. Please check the file name and path.`, 360 | ); 361 | } else if (err === 'INPUT_EMPTY') { 362 | log( 363 | 3, 364 | `input file ${inputFileName} is not opened. Please check the file`, 365 | ); 366 | } else console.error(err); 367 | exit(1); 368 | } 369 | } 370 | 371 | // Create an Object file(*.o) in the desired path 372 | export function makeObjectFile( 373 | outputFolderPath: string, 374 | outputFileName: string, 375 | content: string[], 376 | ) { 377 | /* 378 | if the outputFilePath is /Users/junghaejune/simulator/sample_input/sample/example1.s, 379 | currDirectory : /Users/junghaejune/simulator 380 | outputFolderPath : sample_input/sample 381 | outputFileName: example1.o 382 | content : ['01010', '01010'] 383 | */ 384 | 385 | const currDirectory: string = process.cwd(); 386 | const outputFilePath: string = path.join( 387 | currDirectory, 388 | outputFolderPath, 389 | outputFileName, 390 | ); 391 | 392 | try { 393 | if (fs.existsSync(outputFilePath) === true) { 394 | fs.unlink(outputFilePath, err => { 395 | err 396 | ? console.error(err) 397 | : log(0, `Output file ${outputFileName} exists. Remake the file`); 398 | }); 399 | } else throw 'OUTPUT_NOT_EXISTS'; 400 | const fd: number = fs.openSync(outputFilePath, 'a'); 401 | 402 | content.forEach(item => { 403 | fs.appendFileSync(fd, item + '\n', 'utf-8'); 404 | }); 405 | 406 | fs.closeSync(fd); 407 | } catch (err) { 408 | if (err === 'OUTPUT_NOT_EXISTS') { 409 | log(0, `Output file ${outputFileName} does not exists. Make the file`); 410 | } else console.error(err); 411 | exit(1); 412 | } 413 | } 414 | 415 | export function makeMappingDetail( 416 | assemblyFile: string[], 417 | dataSeg: string[], 418 | textSeg: string[], 419 | mappingTable: number[][], 420 | output: string[], 421 | ) { 422 | const mappingDetail: IMapDetail[] | null = [] as IMapDetail[]; 423 | let textCounter = 0; 424 | 425 | assemblyFile.forEach((assemblyLine, i) => { 426 | const binaryInstructionNumbers: number[] = []; 427 | let binaryInstructions: string[] = []; 428 | 429 | if (assemblyLine.includes('.data')) { 430 | binaryInstructionNumbers.push(0); 431 | binaryInstructions = [output[0]]; 432 | } else if (assemblyLine.includes('.word')) { 433 | const dataSegIndex = dataSeg.indexOf(assemblyLine.split('\t')[2]); 434 | const dataIndex = output.length - dataSeg.length + dataSegIndex; 435 | binaryInstructionNumbers.push(dataIndex); 436 | binaryInstructions = [output[dataIndex]]; 437 | } else if (assemblyLine.includes('.text')) { 438 | binaryInstructionNumbers.push(1); 439 | binaryInstructions = [output[1]]; 440 | } else { 441 | const binaryIndexes = mappingTable[textCounter]; 442 | binaryInstructions = binaryIndexes.map(index => { 443 | binaryInstructionNumbers.push(index + 2); 444 | return output[index + 2]; 445 | }); 446 | assemblyLine === textSeg[textCounter] && textCounter++; 447 | } 448 | 449 | const binaryData: IBinaryData[] = []; 450 | 451 | binaryInstructions.forEach((inst, j) => { 452 | const binaryInstructionIndex = binaryInstructionNumbers[j]; 453 | const temp: IBinaryData = { 454 | lineNumber: binaryInstructionIndex, 455 | data: inst, 456 | }; 457 | 458 | binaryData.push(temp); 459 | }); 460 | 461 | mappingDetail.push({ 462 | key: i, 463 | assembly: assemblyLine, 464 | binary: binaryData, 465 | }); 466 | }); 467 | 468 | return mappingDetail; 469 | } 470 | 471 | /* 472 | assignment2 util 473 | */ 474 | 475 | /* 476 | Procedure: fromBinary 477 | Purpose: From binary to integer 478 | */ 479 | 480 | export function fromBinary(bits: string): number { 481 | return parseInt(bits, 2); 482 | } 483 | 484 | /* 485 | Procedure: memRead 486 | Purpose: read a 32-bit word from memory 487 | */ 488 | 489 | export function memRead(address: number): number { 490 | for (let i = 0; i < MEM_NREGIONS; ++i) { 491 | if ( 492 | address >= memRegions[i].start && 493 | address < memRegions[i].start + memRegions[i].size 494 | ) { 495 | const offset = address - memRegions[i].start; 496 | const result = 497 | (memRegions[i].mem[offset + 3] << 24) | 498 | (memRegions[i].mem[offset + 2] << 16) | 499 | (memRegions[i].mem[offset + 1] << 8) | 500 | (memRegions[i].mem[offset + 0] << 0); 501 | return result; 502 | } 503 | } 504 | } 505 | 506 | /* 507 | Procedure: memWrite 508 | Purpose: Write a 32-bit word to memory 509 | */ 510 | 511 | export function memWrite(address: number, value: number): void { 512 | memRegions.forEach(memRegion => { 513 | if ( 514 | address >= memRegion.start && 515 | address < memRegion.start + memRegion.size 516 | ) { 517 | const offset = address - memRegion.start; 518 | 519 | memRegion.mem[offset + 3] = (value >> 24) & 0xff; 520 | memRegion.mem[offset + 2] = (value >> 16) & 0xff; 521 | memRegion.mem[offset + 1] = (value >> 8) & 0xff; 522 | memRegion.mem[offset + 0] = (value >> 0) & 0xff; 523 | 524 | /* set_offBound */ 525 | memRegion.dirty = true; 526 | if (memRegion.type === MEM_GROW_UP) { 527 | memRegion.offBound = 528 | offset + 4 > memRegion.offBound ? offset + 4 : memRegion.offBound; 529 | } else 530 | memRegion.offBound = 531 | offset + 4 < memRegion.offBound ? offset + 4 : memRegion.offBound; 532 | } 533 | }); 534 | } 535 | 536 | /* 537 | Procedure: memWriteHalf 538 | Purpose: Write a half of 32-bit word to memory 539 | */ 540 | 541 | export function memWriteHalf(address: number, value: number): void { 542 | memRegions.forEach(memRegion => { 543 | if ( 544 | address >= memRegion.start && 545 | address < memRegion.start + memRegion.size 546 | ) { 547 | const offset = address - memRegion.start; 548 | 549 | memRegion.mem[offset + 1] = (value >> 8) & 0xff; 550 | memRegion.mem[offset + 0] = (value >> 0) & 0xff; 551 | 552 | /* set_offBound */ 553 | memRegion.dirty = true; 554 | if (memRegion.type === MEM_GROW_UP) 555 | memRegion.offBound = 556 | offset + 2 > memRegion.offBound ? offset + 2 : memRegion.offBound; 557 | else 558 | memRegion.offBound = 559 | offset + 2 < memRegion.offBound ? offset + 2 : memRegion.offBound; 560 | } 561 | }); 562 | } 563 | 564 | /* 565 | Procedure: initMemory 566 | */ 567 | export function initMemory(): void { 568 | for (let i = 0; i < MEM_NREGIONS; ++i) { 569 | memRegions[i].mem = Array.from({length: memRegions[i].size}, () => 0); 570 | } 571 | } 572 | 573 | /* 574 | Procedure: initInstInfo 575 | */ 576 | export function initInstInfo( 577 | NUM_INST: number, 578 | INST_INFO: Iinstruction[], 579 | ): void { 580 | for (let i = 0; i < NUM_INST; ++i) { 581 | INST_INFO[i].value = 0; 582 | INST_INFO[i].opcode = 0; 583 | INST_INFO[i].funcCode = 0; 584 | INST_INFO[i].rs = 0; 585 | INST_INFO[i].rt = 0; 586 | INST_INFO[i].rd = 0; 587 | INST_INFO[i].imm = 0; 588 | INST_INFO[i].shamt = 0; 589 | INST_INFO[i].target = 0; 590 | } 591 | } 592 | 593 | /* 594 | Procedure: get_inst_info 595 | Purpose: Read instruction information 596 | */ 597 | export function getInstInfo(pc: number): instruction { 598 | return INST_INFO[(pc - MEM_TEXT_START) >> 2]; 599 | } 600 | 601 | /* 602 | Procedure: main process 603 | */ 604 | 605 | export async function mainProcess( 606 | INST_INFO: instruction[], 607 | cycles: number, 608 | CYCLES: simulatorOutputType[], 609 | ): Promise { 610 | let i = cycles; 611 | let result = ''; 612 | 613 | return new Promise((resolve, reject) => { 614 | try { 615 | if (DEBUG_SET) { 616 | console.log(`Simulating for ${cycles} cycles...!\n`); 617 | console.log('MAIN PROCESS', CYCLES); 618 | while (i > 0) { 619 | cycle(); 620 | rdump(); 621 | 622 | if (MEM_DUMP_SET) dumpMemory(); 623 | 624 | i -= 1; 625 | 626 | if (RUN_BIT === 0) break; 627 | } 628 | } else { 629 | running(i, CYCLES); 630 | result += rdump(); 631 | 632 | if (MEM_DUMP_SET) { 633 | result += dumpMemory(); 634 | } 635 | 636 | let EachCycle: string = rdump(); 637 | if (MEM_DUMP_SET) EachCycle += dumpMemory(); 638 | CYCLES.push(parseSimulatorOutput(EachCycle)); 639 | } 640 | const returnObject = parseSimulatorOutput(result); 641 | resolve(returnObject); 642 | } catch (error) { 643 | reject(error); 644 | } 645 | }); 646 | } 647 | 648 | /* 649 | Procedure: cycle 650 | Purpose: Execute a cycle 651 | */ 652 | 653 | export function cycle(): void { 654 | process_instruction(); 655 | instAddOne(); 656 | } 657 | 658 | export function dumpMemory(): string { 659 | let dump_string = ''; 660 | if (memData.dirty) { 661 | const dstart = memData.start; 662 | const dstop = memData.start + memData.offBound; 663 | dump_string += `Data section\n`; 664 | dump_string += mdump(dstart, dstop); 665 | dump_string += '\n'; 666 | } 667 | 668 | if (memStack.dirty) { 669 | const dstart = memStack.start + memStack.offBound; 670 | const dstop = memStack.start + memStack.size - 4; 671 | dump_string += `Stack section\n`; 672 | dump_string += mdump(dstart, dstop); 673 | dump_string += '\n'; 674 | } 675 | 676 | return dump_string; 677 | } 678 | 679 | /* 680 | Procedure: mdump 681 | Purpose: Dump a word-aligned region of memory to the output file. 682 | */ 683 | export function mdump(start: number, stop: number): string { 684 | let mdump_string = ''; 685 | for (let i = start; i < stop + 1; i += 4) { 686 | mdump_string += `0x${toHexAndPad(i)}: 0x${toHexAndPad(memRead(i))}\n`; 687 | } 688 | mdump_string += '\n'; 689 | return mdump_string; 690 | } 691 | 692 | /* 693 | Procedure: rdump 694 | Purpose: Dump current register and bus values to the output file. 695 | */ 696 | export function rdump(): string { 697 | let rdump_string = ''; 698 | rdump_string += 'Program Counter\n'; 699 | rdump_string += `PC: 0x${toHexAndPad(currentState.PC)}\n`; 700 | rdump_string += `Registers\n`; 701 | 702 | for (let k = 0; k < MIPS_REGS; ++k) { 703 | rdump_string += `R${k}: 0x${toHexAndPad((currentState.REGS[k] >>>= 0))}\n`; 704 | } 705 | 706 | rdump_string += '\n'; 707 | return rdump_string; 708 | } 709 | 710 | /* 711 | Procedure: run n 712 | Purpose: Simulate MIPS for n cycles 713 | */ 714 | export function running(num_cycles: number, CYCLES: simulatorOutputType[]) { 715 | let running_string = ''; 716 | if (RUN_BIT === 0) { 717 | running_string = "Can't simulate, Simulator is halted\n"; 718 | } 719 | 720 | running_string = `Simulating for ${num_cycles} cycles...!\n\n`; 721 | 722 | for (let i = 0; i < num_cycles; ++i) { 723 | if (RUN_BIT === 0) { 724 | running_string += `Simulator halted ${i}th cycle.\n\n`; 725 | break; 726 | } 727 | let EachCycle: string = rdump(); 728 | if (MEM_DUMP_SET) EachCycle += dumpMemory(); 729 | CYCLES.push(parseSimulatorOutput(EachCycle)); 730 | cycle(); 731 | } 732 | console.log(running_string); 733 | } 734 | -------------------------------------------------------------------------------- /tests/integration/assembler.test.ts: -------------------------------------------------------------------------------- 1 | import {assemble} from '@root/index'; 2 | import {resetSymbolTable} from '@utils/constants'; 3 | import {makeInput, makeOutput, IMapDetail} from '@utils/functions'; 4 | 5 | const mappingDetailOutput: IMapDetail[] = [ 6 | { 7 | key: 0, 8 | assembly: '\t.data', 9 | binary: [{lineNumber: 0, data: '00000000000000000000000001011000'}], 10 | }, 11 | { 12 | key: 1, 13 | assembly: 'data1:\t.word\t100', 14 | binary: [{lineNumber: 24, data: '00000000000000000000000001100100'}], 15 | }, 16 | { 17 | key: 2, 18 | assembly: 'data2:\t.word\t200', 19 | binary: [{lineNumber: 25, data: '00000000000000000000000011001000'}], 20 | }, 21 | { 22 | key: 3, 23 | assembly: 'data3:\t.word\t0x12345678', 24 | binary: [{lineNumber: 26, data: '00010010001101000101011001111000'}], 25 | }, 26 | { 27 | key: 4, 28 | assembly: '\t.text', 29 | binary: [{lineNumber: 1, data: '00000000000000000000000000001100'}], 30 | }, 31 | { 32 | key: 5, 33 | assembly: 'main:', 34 | binary: [{lineNumber: 2, data: '00000010001000001000100000100100'}], 35 | }, 36 | { 37 | key: 6, 38 | assembly: '\tand\t$17, $17, $0', 39 | binary: [{lineNumber: 2, data: '00000010001000001000100000100100'}], 40 | }, 41 | { 42 | key: 7, 43 | assembly: '\tand\t$18, $18, $0', 44 | binary: [{lineNumber: 3, data: '00000010010000001001000000100100'}], 45 | }, 46 | { 47 | key: 8, 48 | assembly: '\tla\t$8, data1', 49 | binary: [{lineNumber: 4, data: '00111100000010000001000000000000'}], 50 | }, 51 | { 52 | key: 9, 53 | assembly: '\tla\t$9, data2', 54 | binary: [ 55 | {lineNumber: 5, data: '00111100000010010001000000000000'}, 56 | {lineNumber: 6, data: '00110101001010010000000000000100'}, 57 | ], 58 | }, 59 | { 60 | key: 10, 61 | assembly: '\tand\t$10, $10, $0', 62 | binary: [{lineNumber: 7, data: '00000001010000000101000000100100'}], 63 | }, 64 | { 65 | key: 11, 66 | assembly: 'lab1:', 67 | binary: [{lineNumber: 8, data: '00000001011000000101100000100100'}], 68 | }, 69 | { 70 | key: 12, 71 | assembly: '\tand\t$11, $11, $0', 72 | binary: [{lineNumber: 8, data: '00000001011000000101100000100100'}], 73 | }, 74 | { 75 | key: 13, 76 | assembly: 'lab2:', 77 | binary: [{lineNumber: 9, data: '00100010001100010000000000000001'}], 78 | }, 79 | { 80 | key: 14, 81 | assembly: '\taddi\t$17, $17, 0x1', 82 | binary: [{lineNumber: 9, data: '00100010001100010000000000000001'}], 83 | }, 84 | { 85 | key: 15, 86 | assembly: '\taddi\t$11, $11, 0x1', 87 | binary: [{lineNumber: 10, data: '00100001011010110000000000000001'}], 88 | }, 89 | { 90 | key: 16, 91 | assembly: '\tor\t$9, $9, $0', 92 | binary: [{lineNumber: 11, data: '00000001001000000100100000100101'}], 93 | }, 94 | { 95 | key: 17, 96 | assembly: '\tbne\t$11, $8, lab2', 97 | binary: [{lineNumber: 12, data: '00010101011010001111111111111100'}], 98 | }, 99 | { 100 | key: 18, 101 | assembly: 'lab3:', 102 | binary: [{lineNumber: 13, data: '00100010010100100000000000000010'}], 103 | }, 104 | { 105 | key: 19, 106 | assembly: '\taddi\t$18, $18, 0x2', 107 | binary: [{lineNumber: 13, data: '00100010010100100000000000000010'}], 108 | }, 109 | { 110 | key: 20, 111 | assembly: '\taddi\t$11, $11, 1', 112 | binary: [{lineNumber: 14, data: '00100001011010110000000000000001'}], 113 | }, 114 | { 115 | key: 21, 116 | assembly: '\tsll\t$18, $17, 1', 117 | binary: [{lineNumber: 15, data: '00000000000100011001000001000000'}], 118 | }, 119 | { 120 | key: 22, 121 | assembly: '\tsrl\t$17, $18, 1', 122 | binary: [{lineNumber: 16, data: '00000000000100101000100001000010'}], 123 | }, 124 | { 125 | key: 23, 126 | assembly: '\tand\t$19, $17, $18', 127 | binary: [{lineNumber: 17, data: '00000010001100101001100000100100'}], 128 | }, 129 | { 130 | key: 24, 131 | assembly: '\tbne\t$11, $9, lab3', 132 | binary: [{lineNumber: 18, data: '00010101011010011111111111111010'}], 133 | }, 134 | { 135 | key: 25, 136 | assembly: 'lab4:', 137 | binary: [{lineNumber: 19, data: '00000000101111110010100000100000'}], 138 | }, 139 | { 140 | key: 26, 141 | assembly: '\tadd\t$5, $5, $31', 142 | binary: [{lineNumber: 19, data: '00000000101111110010100000100000'}], 143 | }, 144 | { 145 | key: 27, 146 | assembly: '\tnor\t$16, $17, $18', 147 | binary: [{lineNumber: 20, data: '00000010001100101000000000100111'}], 148 | }, 149 | { 150 | key: 28, 151 | assembly: '\tbeq\t$10, $8, lab5', 152 | binary: [{lineNumber: 21, data: '00010001010010000000000000000001'}], 153 | }, 154 | { 155 | key: 29, 156 | assembly: '\tj\tlab1', 157 | binary: [{lineNumber: 22, data: '00001000000100000000000000000110'}], 158 | }, 159 | { 160 | key: 30, 161 | assembly: 'lab5:', 162 | binary: [{lineNumber: 23, data: '00110110000100001111000011110000'}], 163 | }, 164 | { 165 | key: 31, 166 | assembly: '\tori\t$16, $16, 0xf0f0', 167 | binary: [{lineNumber: 23, data: '00110110000100001111000011110000'}], 168 | }, 169 | ]; 170 | 171 | test(`testing example 1 for [mapping detail]`, () => { 172 | resetSymbolTable(); 173 | 174 | const input = makeInput('sample_input', `example1.s`); 175 | const {mappingDetail} = assemble(input, true); 176 | 177 | expect(mappingDetail).toEqual(mappingDetailOutput); 178 | }); 179 | 180 | for (let i = 1; i <= 7; i++) { 181 | test(`testing example ${i} for [array output]`, () => { 182 | resetSymbolTable(); 183 | 184 | const input = makeInput('sample_input', `example${i}.s`); 185 | const {output} = assemble(input, true); 186 | const testOutput = makeOutput('sample_output', `example${i}.o`) 187 | .split('\n') // string -> string[] 전환 188 | .filter(ele => ele); // "" deleted, "" == false 189 | 190 | expect(output).toEqual(testOutput); 191 | }); 192 | } 193 | -------------------------------------------------------------------------------- /tests/integration/simulator.test.ts: -------------------------------------------------------------------------------- 1 | import {simulator} from '@root/index'; 2 | import {initializeMem} from '@utils/constants'; 3 | import {makeInput, makeOutput, parseSimulatorOutput} from '@utils/functions'; 4 | 5 | for (let i = 1; i <= 7; i++) { 6 | initializeMem(); 7 | test(`testing example ${i}`, async () => { 8 | const input = makeInput('sample_input', `example${i}.s`); 9 | const {history} = await simulator(input, 10000, true); 10 | const expectOutput = parseSimulatorOutput( 11 | makeOutput('simulator_sample_output', `example0${i}.o`), 12 | ); 13 | const testOutput = history[history.length - 1]; 14 | expect(expectOutput.toString()).toBe(testOutput.toString()); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /tests/unit/makeSymbolTable.test.ts: -------------------------------------------------------------------------------- 1 | import {makeSymbolTable} from '@src/simulator/assembler'; 2 | import {resetSymbolTable, SYMBOL_TABLE} from '@src/utils/constants'; 3 | 4 | const testInput = [ 5 | '\t.data', 6 | 'data1:\t.word\t100', 7 | 'data2:\t.word\t200', 8 | 'data3:\t.word\t0x12345678', 9 | '\t.text', 10 | 'main:', 11 | '\tand\t$17, $17, $0', 12 | '\tand\t$18, $18, $0', 13 | '\tla\t$8, data1', 14 | '\tla\t$9, data2', 15 | '\tand\t$10, $10, $0', 16 | 'lab1:', 17 | '\tand\t$11, $11, $0', 18 | 'lab2:', 19 | '\taddi\t$17, $17, 0x1', 20 | '\taddi\t$11, $11, 0x1', 21 | '\tor\t$9, $9, $0', 22 | '\tbne\t$11, $8, lab2', 23 | 'lab3:', 24 | '\taddi\t$18, $18, 0x2', 25 | '\taddi\t$11, $11, 1', 26 | '\tsll\t$18, $17, 1', 27 | '\tsrl\t$17, $18, 1', 28 | '\tand\t$19, $17, $18', 29 | '\tbne\t$11, $9, lab3', 30 | 'lab4:', 31 | '\tadd\t$5, $5, $31', 32 | '\tnor\t$16, $17, $18', 33 | '\tbeq\t$10, $8, lab5', 34 | '\tj\tlab1', 35 | 'lab5:', 36 | '\tori\t$16, $16, 0xf0f0', 37 | ]; 38 | 39 | const symbolTableCase = { 40 | symbolTable: { 41 | data1: 268435456, 42 | data2: 268435460, 43 | data3: 268435464, 44 | main: 4194304, 45 | lab1: 4194328, 46 | lab2: 4194332, 47 | lab3: 4194348, 48 | lab4: 4194372, 49 | lab5: 4194388, 50 | }, 51 | dataSeg: ['100', '200', '0x12345678'], 52 | textSeg: [ 53 | '\tand\t$17, $17, $0', 54 | '\tand\t$18, $18, $0', 55 | '\tla\t$8, data1', 56 | '\tla\t$9, data2', 57 | '\tand\t$10, $10, $0', 58 | '\tand\t$11, $11, $0', 59 | '\taddi\t$17, $17, 0x1', 60 | '\taddi\t$11, $11, 0x1', 61 | '\tor\t$9, $9, $0', 62 | '\tbne\t$11, $8, lab2', 63 | '\taddi\t$18, $18, 0x2', 64 | '\taddi\t$11, $11, 1', 65 | '\tsll\t$18, $17, 1', 66 | '\tsrl\t$17, $18, 1', 67 | '\tand\t$19, $17, $18', 68 | '\tbne\t$11, $9, lab3', 69 | '\tadd\t$5, $5, $31', 70 | '\tnor\t$16, $17, $18', 71 | '\tbeq\t$10, $8, lab5', 72 | '\tj\tlab1', 73 | '\tori\t$16, $16, 0xf0f0', 74 | ], 75 | dataSectionSize: 12, 76 | textSectionSize: 88, 77 | }; 78 | 79 | test('testing makeSymbolTable', () => { 80 | resetSymbolTable(); 81 | 82 | const {dataSeg, textSeg, dataSectionSize, textSectionSize} = 83 | makeSymbolTable(testInput); 84 | 85 | expect(dataSeg).toEqual(symbolTableCase.dataSeg); 86 | expect(textSeg).toEqual(symbolTableCase.textSeg); 87 | expect(dataSectionSize).toBe(symbolTableCase.dataSectionSize); 88 | expect(textSectionSize).toBe(symbolTableCase.textSectionSize); 89 | expect(SYMBOL_TABLE).toEqual(symbolTableCase.symbolTable); 90 | 91 | resetSymbolTable(); 92 | }); 93 | -------------------------------------------------------------------------------- /tests/unit/recordDataSection.test.ts: -------------------------------------------------------------------------------- 1 | import {makeSymbolTable, recordDataSection} from '@src/simulator/assembler'; 2 | import {resetSymbolTable} from '@src/utils/constants'; 3 | 4 | const testInput = [ 5 | '\t.data', 6 | 'data1:\t.word\t100', 7 | 'data2:\t.word\t200', 8 | 'data3:\t.word\t0x12345678', 9 | '\t.text', 10 | 'main:', 11 | '\tand\t$17, $17, $0', 12 | '\tand\t$18, $18, $0', 13 | '\tla\t$8, data1', 14 | '\tla\t$9, data2', 15 | '\tand\t$10, $10, $0', 16 | 'lab1:', 17 | '\tand\t$11, $11, $0', 18 | 'lab2:', 19 | '\taddi\t$17, $17, 0x1', 20 | '\taddi\t$11, $11, 0x1', 21 | '\tor\t$9, $9, $0', 22 | '\tbne\t$11, $8, lab2', 23 | 'lab3:', 24 | '\taddi\t$18, $18, 0x2', 25 | '\taddi\t$11, $11, 1', 26 | '\tsll\t$18, $17, 1', 27 | '\tsrl\t$17, $18, 1', 28 | '\tand\t$19, $17, $18', 29 | '\tbne\t$11, $9, lab3', 30 | 'lab4:', 31 | '\tadd\t$5, $5, $31', 32 | '\tnor\t$16, $17, $18', 33 | '\tbeq\t$10, $8, lab5', 34 | '\tj\tlab1', 35 | 'lab5:', 36 | '\tori\t$16, $16, 0xf0f0', 37 | ]; 38 | 39 | const recordDataCase = ['100', '200', '0x12345678']; 40 | 41 | const recordDataOutput = [ 42 | '00000000000000000000000001100100', 43 | '00000000000000000000000011001000', 44 | '00010010001101000101011001111000', 45 | ]; 46 | 47 | test('testing recordDataSection', () => { 48 | resetSymbolTable(); 49 | makeSymbolTable(testInput); 50 | 51 | const output = recordDataSection(recordDataCase); 52 | expect(output).toEqual(recordDataOutput); 53 | }); 54 | -------------------------------------------------------------------------------- /tests/unit/recordTextSection.test.ts: -------------------------------------------------------------------------------- 1 | import {makeSymbolTable, recordTextSection} from '@src/simulator/assembler'; 2 | import {resetSymbolTable} from '@src/utils/constants'; 3 | 4 | const testInput = [ 5 | '\t.data', 6 | 'data1:\t.word\t100', 7 | 'data2:\t.word\t200', 8 | 'data3:\t.word\t0x12345678', 9 | '\t.text', 10 | 'main:', 11 | '\tand\t$17, $17, $0', 12 | '\tand\t$18, $18, $0', 13 | '\tla\t$8, data1', 14 | '\tla\t$9, data2', 15 | '\tand\t$10, $10, $0', 16 | 'lab1:', 17 | '\tand\t$11, $11, $0', 18 | 'lab2:', 19 | '\taddi\t$17, $17, 0x1', 20 | '\taddi\t$11, $11, 0x1', 21 | '\tor\t$9, $9, $0', 22 | '\tbne\t$11, $8, lab2', 23 | 'lab3:', 24 | '\taddi\t$18, $18, 0x2', 25 | '\taddi\t$11, $11, 1', 26 | '\tsll\t$18, $17, 1', 27 | '\tsrl\t$17, $18, 1', 28 | '\tand\t$19, $17, $18', 29 | '\tbne\t$11, $9, lab3', 30 | 'lab4:', 31 | '\tadd\t$5, $5, $31', 32 | '\tnor\t$16, $17, $18', 33 | '\tbeq\t$10, $8, lab5', 34 | '\tj\tlab1', 35 | 'lab5:', 36 | '\tori\t$16, $16, 0xf0f0', 37 | ]; 38 | 39 | const recordTextCase = [ 40 | ' and $17, $17, $0', 41 | ' and $18, $18, $0', 42 | ' la $8, data1', 43 | ' la $9, data2', 44 | ' and $10, $10, $0', 45 | ' and $11, $11, $0', 46 | ' addi $17, $17, 0x1', 47 | ' addi $11, $11, 0x1', 48 | ' or $9, $9, $0', 49 | ' bne $11, $8, lab2', 50 | ' addi $18, $18, 0x2', 51 | ' addi $11, $11, 1', 52 | ' sll $18, $17, 1', 53 | ' srl $17, $18, 1', 54 | ' and $19, $17, $18', 55 | ' bne $11, $9, lab3', 56 | ' add $5, $5, $31', 57 | ' nor $16, $17, $18', 58 | ' beq $10, $8, lab5', 59 | ' j lab1', 60 | ' ori $16, $16, 0xf0f0', 61 | ]; 62 | 63 | const recordTextOutput = [ 64 | '00000010001000001000100000100100', 65 | '00000010010000001001000000100100', 66 | '00111100000010000001000000000000', 67 | '00111100000010010001000000000000', 68 | '00110101001010010000000000000100', 69 | '00000001010000000101000000100100', 70 | '00000001011000000101100000100100', 71 | '00100010001100010000000000000001', 72 | '00100001011010110000000000000001', 73 | '00000001001000000100100000100101', 74 | '00010101011010001111111111111100', 75 | '00100010010100100000000000000010', 76 | '00100001011010110000000000000001', 77 | '00000000000100011001000001000000', 78 | '00000000000100101000100001000010', 79 | '00000010001100101001100000100100', 80 | '00010101011010011111111111111010', 81 | '00000000101111110010100000100000', 82 | '00000010001100101000000000100111', 83 | '00010001010010000000000000000001', 84 | '00001000000100000000000000000110', 85 | '00110110000100001111000011110000', 86 | ]; 87 | 88 | const mappingTableOutput = [ 89 | [0], 90 | [1], 91 | [2], 92 | [3, 4], 93 | [5], 94 | [6], 95 | [7], 96 | [8], 97 | [9], 98 | [10], 99 | [11], 100 | [12], 101 | [13], 102 | [14], 103 | [15], 104 | [16], 105 | [17], 106 | [18], 107 | [19], 108 | [20], 109 | [21], 110 | ]; 111 | 112 | test('testing recordTextSection [binary Text]', () => { 113 | resetSymbolTable(); 114 | makeSymbolTable(testInput); 115 | 116 | const [binaryText, _] = recordTextSection(recordTextCase); 117 | expect(binaryText).toEqual(recordTextOutput); 118 | }); 119 | 120 | test('testing recordTextSection [mapping Table]', () => { 121 | resetSymbolTable(); 122 | makeSymbolTable(testInput); 123 | 124 | const [_, mappingTable] = recordTextSection(recordTextCase); 125 | expect(mappingTable).toEqual(mappingTableOutput); 126 | }); 127 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // "types": ["jest"], 4 | "module": "CommonJS", 5 | "allowJs": true, 6 | "declaration": true, 7 | "target": "ES5", 8 | "outDir": "./dist", 9 | "rootDir": "./", 10 | "moduleResolution": "Node", 11 | "lib": ["ES2015", "DOM", "DOM.Iterable"], 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": false, 14 | "baseUrl": "./", 15 | "paths": { 16 | "@root/*": ["./*"], 17 | "@src/*": ["src/*"], 18 | "@utils/*": ["src/utils/*"], 19 | "@simulator/*": ["src/simulator/*"] 20 | } 21 | }, 22 | "include": ["./src/**/*.ts", "./tests/**/*.ts"], 23 | "files": ["index.ts"], 24 | "exclude": ["node_modules", "dist", ".github"] 25 | } 26 | -------------------------------------------------------------------------------- /typescript.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["jest"] 5 | } 6 | } 7 | --------------------------------------------------------------------------------