├── .dockerignore ├── .github └── workflows │ └── dotnetcore.yml ├── .gitignore ├── .idea └── .idea.sim6502 │ ├── .idea │ ├── .gitignore │ ├── contentModel.xml │ ├── indexLayout.xml │ ├── inspectionProfiles │ │ └── Project_Default.xml │ ├── misc.xml │ ├── modules.xml │ ├── projectSettingsUpdater.xml │ └── vcs.xml │ └── riderModule.iml ├── Dockerfile ├── Makefile ├── README.md ├── dependencies ├── NCalc.dll ├── NCalc.pdb └── antlr-4.8-complete.jar ├── example ├── Makefile ├── README.md ├── include_me_full.prg ├── include_me_full.sym └── tests.6502 ├── sim6502.sln ├── sim6502.sln.DotSettings ├── sim6502 ├── Expressions │ ├── BaseCompare.cs │ ├── ComparisonResult.cs │ └── MemoryCompare.cs ├── Grammar │ ├── Generated │ │ ├── sim6502.interp │ │ ├── sim6502.tokens │ │ ├── sim6502BaseListener.cs │ │ ├── sim6502Lexer.cs │ │ ├── sim6502Lexer.interp │ │ ├── sim6502Lexer.tokens │ │ ├── sim6502Listener.cs │ │ └── sim6502Parser.cs │ ├── SimBaseListener.cs │ ├── SimErrorListener.cs │ └── sim6502.g4 ├── Proc │ ├── AddressingMode.cs │ ├── Disassembly.cs │ ├── LoadableResource.cs │ └── Processor.cs ├── Sim6502CLI.cs ├── Utilities │ ├── SymbolFile.cs │ └── Utility.cs ├── nlog.config └── sim6502.csproj └── sim6502tests ├── GrammarTests ├── test-1.txt ├── test-10.txt ├── test-2.txt ├── test-3.txt ├── test-4.txt ├── test-5.txt ├── test-6.txt ├── test-7.txt ├── test-8.txt └── test-9.txt ├── ProcessorTests.cs ├── RegisterMode.cs ├── SymbolFileTests.cs ├── TestPrograms ├── include_me_full.prg └── include_me_full.sym ├── TestSuiteParser.cs ├── UtilityTests.cs ├── nlog.config └── sim6502tests.csproj /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | README.md 3 | sim6502/bin/** 4 | sim6502/obj/** 5 | sim6502tests/bin/** 6 | sim6502tests/obj/** -------------------------------------------------------------------------------- /.github/workflows/dotnetcore.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: mr-smithers-excellent/docker-build-push@v2 17 | with: 18 | image: barrywalker71/sim6502cli 19 | tag: latest 20 | registry: registry.hub.docker.com 21 | dockerfile: Dockerfile 22 | username: ${{ secrets.DOCKER_USERNAME }} 23 | password: ${{ secrets.DOCKER_PASSWORD }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | /packages/ -------------------------------------------------------------------------------- /.idea/.idea.sim6502/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml -------------------------------------------------------------------------------- /.idea/.idea.sim6502/.idea/contentModel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /.idea/.idea.sim6502/.idea/indexLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/.idea.sim6502/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/.idea.sim6502/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/.idea.sim6502/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/.idea.sim6502/.idea/projectSettingsUpdater.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/.idea.sim6502/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.idea.sim6502/riderModule.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/core/sdk:3.1 2 | 3 | WORKDIR /app 4 | 5 | COPY . /app/ 6 | RUN dotnet build /app/sim6502.sln -c Release 7 | RUN dotnet test /app/sim6502.sln -c Release 8 | 9 | ENTRYPOINT ["dotnet","/app/sim6502/bin/Release/netcoreapp3.0/Sim6502TestRunner.dll"] 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | grammar: 2 | cd sim6502/Grammar && \ 3 | java -jar ../../dependencies/antlr-4.8-complete.jar -Dlanguage=CSharp -listener \ 4 | -o Generated -package sim6502.Grammar.Generated sim6502.g4 && \ 5 | cd ../.. 6 | 7 | build: grammar 8 | docker build . -t barrywalker71/sim6502cli:latest 9 | 10 | push: build 11 | docker push barrywalker71/sim6502cli:latest 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | __ _____ ___ ___ _ _ _ _ _______ _ _____ _ _____ 2 | / /| ____|/ _ \__ \ | | | | (_) | |__ __| | | / ____| | |_ _| 3 | / /_| |__ | | | | ) | | | | |_ __ _| |_ | | ___ ___| |_ | | | | | | 4 | | '_ \___ \| | | |/ / | | | | '_ \| | __| | |/ _ \/ __| __| | | | | | | 5 | | (_) |__) | |_| / /_ | |__| | | | | | |_ | | __/\__ \ |_ | |____| |____ _| |_ 6 | \___/____/ \___/____| \____/|_| |_|_|\__| |_|\___||___/\__| \_____|______|_____| 7 | 8 | 9 | ![.NET Core](https://github.com/barryw/sim6502/workflows/.NET%20Core/badge.svg) 10 | 11 | #### Introduction 12 | 13 | This is a tool to help you unit test your 6502 assembly language programs. There's no valid reason why your 6502 programs shouldn't receive the same DevOps treatment as the rest of your modern applications. 14 | 15 | It works by running your assembled programs with a 6502 simulator and then allowing you to make assertions on memory and CPU state. It's very similar to other unit test tools. 16 | 17 | A minimal test suite looks like this: 18 | 19 | ``` 20 | suites { 21 | suite("Tests against hardware register library") { 22 | ; Load the program under test 23 | symbols("/code/include_me_full_r.sym") 24 | load("/code/include_me_full_r.prg") 25 | load("/code/kernal.rom", address = $e000) 26 | 27 | test("sprites-positions-correctly-without-msb","Sprite X pos < 256 sets MSB to 0") { 28 | x = $00 29 | a = $ff 30 | y = $00 31 | $02 = $40 32 | [vic.MSIGX] = $00 33 | 34 | jsr([PositionSprite], stop_on_rts = true, fail_on_brk = true) 35 | 36 | assert([vic.SP0X] == $ff, "Sprite 0's X pos is at ff") 37 | assert([vic.SP0Y] == $40, "Sprite 0's Y pos is at $40") 38 | assert([vic.MSIGX] == $00, "And sprite 0's MSB is set to 0") 39 | } 40 | } 41 | 42 | suite("Tests against pseudo register library") { 43 | ; Load the program under test 44 | symbols("/code/include_me_full.sym") 45 | load("/code/include_me_full.prg", strip_header = true) 46 | load("/code/kernal.rom", address = $e000) 47 | 48 | test("memory-fill-1", "Fill an uneven block of memory") { 49 | [r0L] = $bd ; Stuff $bd into our memory locations. Odd number, right? 50 | [r1] = $1234 ; Start at $1234 51 | [r2] = $12c ; and do 300 bytes 52 | 53 | jsr([FillMemory], stop_on_rts = true, fail_on_brk = true) 54 | 55 | assert(cycles < 11541, "We can fill this block in fewer than 11541 cycles") 56 | assert(memchk($1234, $12c, $bd), "Memory was filled properly") 57 | } 58 | } 59 | } 60 | 61 | ``` 62 | 63 | Each file can contain one or more `suite`s and each suite can contain one more more `test`s. Each suite is tied to a set of binary object files that are the subjects to be tested. 64 | 65 | Start your suite by giving it a name. Call it whatever you'd like since the name isn't significant. It's used to identify the suite in output. 66 | 67 | ``` 68 | suites { 69 | suite("My awesome new test suite! Sweet!") { 70 | } 71 | } 72 | ``` 73 | 74 | Inside the suite you'll first need to define the programs that you'd like to test. You can also load other things that your test code may need. You can include things like the C64 KERNAL, BASIC, etc. 75 | 76 | ``` 77 | suites { 78 | suite("My awesome new test suite! Sweet!") { 79 | load("/code/include_me_full.prg", strip_header = true) 80 | load("/code/kernal.rom", address = $e000) 81 | } 82 | } 83 | ``` 84 | 85 | If you don't specify the binary file's `address`, it will be inferred by looking at the first 2 bytes of the file. These will be the 16-bit load address. If you don't specify `address`, then you'll need to specify `strip_header = true` so that those 2 bytes are removed before loading to memory. 86 | 87 | You can also include a kickassembler symbol file so that you can use symbol references instead of hardcoded values and addresses. 88 | 89 | ``` 90 | suites { 91 | suite("My awesome new test suite! Sweet!") { 92 | symbols("/code/include_me_full.sym") 93 | load("/code/include_me_full.prg", strip_header = true) 94 | load("/code/kernal.rom", address = $e000) 95 | } 96 | } 97 | ``` 98 | 99 | Next, start writing your tests. Tests have 3 main blocks: memory assignment, calling subroutines, assertions. You use the memory assignment area to set things up to test your code. Once memory is set up, you can then call subroutines in the code you want to test. When the subroutine's exit condition is reached, assertions will be performed to make sure your code did what it was supposed to. Here's an example: 100 | 101 | ``` 102 | suites { 103 | suite("My awesome new test suite! Sweet!") { 104 | ; Any line that starts with a semi-colon is treated as a comment 105 | symbols("/code/include_me_full.sym") 106 | load("/code/include_me_full.prg", strip_header = true) 107 | load("/code/kernal.rom", address = $e000) 108 | 109 | test("memory-fill-1", "Fill an uneven block of memory") { 110 | [r0L] = $bd ; Stuff $bd into our memory locations. Odd number, right? 111 | [r1] = $1234 ; Start at $1234 112 | [r2] = $12c ; and do 300 bytes 113 | 114 | jsr([FillMemory], stop_on_rts = true, fail_on_brk = true) 115 | 116 | assert(cycles < 11541, "We can fill this block in fewer than 11541 cycles") 117 | assert(memchk($1234, $12c, $bd), "Memory was filled properly") 118 | } 119 | } 120 | } 121 | ``` 122 | 123 | This code contains a single test in a single suite. The test is named `memory-fill-1` and has a description of `Fill an uneven block of memory`. These are not significant and are only used to identify the test in output. 124 | 125 | The first 3 lines of the test are memory assignment lines. They refer to symbols contained in the symbol file `include_me_full.sym`, which must exist or the test fails. 126 | 127 | Once these symbols are resolved to a location, the value to the right of the equals sign is placed in that memory location. If the value is > 255, then a 16-bit word is placed at the symbol location and symbol location +1 ([r1] & [r1] + 1). 128 | 129 | The `jsr` line will start executing code starting at the address given, which in this case is a symbol called `FillMemory`. The `jsr` function can take 3 parameters: 130 | 131 | - stop_on_rts = true|false : Whether to stop executing when a `rts` instruction is encountered. The code will only return if the `rts` instruction exists at the same level as the subroutine. For example, if your subroutine calls other routines, those `rts` calls won't trigger the jsr to exit. 132 | - stop_on_address = address : If specified, the jsr call will return when the program counter reaches this address. 133 | - fail_on_brk = true|false : Whether to fail the test if a `brk` instruction is encountered. 134 | 135 | 136 | Once your subroutine exits, the assertions will be run in order. You can assert any of these things: 137 | 138 | - memory location values using either the address or a symbol reference (eg. `[vic.SP0X] == $01` or `$3000 == $80`) 139 | - processor cycle counts to ensure that code performs as expected (eg. `cycles < 80`) 140 | - memory compares to verify that copy operations work correctly (eg. `assert(memcmp($e000, $4000, $2000), "Ensure that KERNAL was copied correctly")`) 141 | - memory check to verify that fill operations work correctly (eg. `assert(memchk($1234, $12c, $bd), "Memory was filled properly")`) 142 | 143 | The expression syntax is very flexible so that you can do things like this: 144 | 145 | ``` 146 | assert([c64lib_timers] + $00 + peekbyte([r2H]) * 8 == [ENABLE], "Timer enabled") 147 | assert([c64lib_timers] + $01 + peekbyte([r2H]) * 8 == [TIMER_SINGLE], "Timer type is single") 148 | assert(([c64lib_timers] + $02 + peekbyte([r2H]) * 8).w == $1000, "Timer's current value") 149 | assert(([c64lib_timers] + $04 + peekbyte([r2H]) * 8).w == $1000, "Timer's frequency") 150 | assert(([c64lib_timers] + $06 + peekbyte([r2H]) * 8).w == [ReadJoysticks], "Timer's callback address") 151 | ``` 152 | 153 | You can tell the CLI whether to return a byte or a word from a memory location by using the `.b` and `.w` suffix on the address expression. By default, a byte will be returned. (eg. `[MyVector].w`) 154 | 155 | You can also return the hi and lo byte for 16-bit number by using the `.l` and `.h` suffix (eg. `[MyVector].h`) 156 | 157 | #### Running 158 | 159 | You'll need to have the following things available to the test CLI: 160 | 161 | - Your assembled 6502 program in .prg format. If the first 2 bytes don't contain the load address, then you'll need to specify the address with the `address` parameter. 162 | - Your Kickassembler symbol file. While not required, makes testing a LOT easier! 163 | - Your test file 164 | 165 | Run the CLI with: 166 | 167 | ```bash 168 | dotnet Sim6502TestRunner.dll -s {path to your test script} 169 | ``` 170 | 171 | If all of your tests pass, the CLI will exit with a return code of 0. If any tests fail, it will return with a 1. 172 | 173 | If you'd like to see the assembly language instructions that it executes while running your tests, add the `-t` flag: 174 | 175 | ```bash 176 | dotnet Sim6502TestRunner.dll -t -s {path to your test script} 177 | ``` 178 | 179 | There is also a docker image if you'd like to not have to mess with installing the .NET Core framework. You can run it like this: 180 | 181 | ```bash 182 | docker run -v ${PWD}:/code -it barrywalker71/sim6502cli:latest -s /code/{your test script} -t 183 | ``` 184 | 185 | That would mount the current directory to a directory in the container called `/code` and would expect to see all of your artifacts there, unless you've given them absolute paths. Just make sure you update your test script to point to the correct location of any roms and programs. 186 | 187 | If you'd like to see a larger example of this tool in action, run `make` from the `example` folder. It's the test suite from my c64lib project. 188 | 189 | 190 | ##### Function Reference 191 | 192 | - memcmp(source, target, size): Compare 2 blocks of memory 193 | - memchk(source, size, value): Ensure that a block of memory contains `value` 194 | - peekbyte(address): Return the 8-bit value at `address` 195 | - peekword(address): Return the 16-bit value at `address` and `address + 1` 196 | 197 | 198 | ##### Symbol File Reference 199 | 200 | The only supported symbol file right now is Kickassembler's. To load symbols from a symbol file, load it from the top of your suite with the `symbols` function: 201 | 202 | ``` 203 | symbols("/code/include_me_full.sym") 204 | ``` 205 | 206 | You can reference symbols within your tests by wrapping the symbol name in brackets: 207 | 208 | ``` 209 | [MySymbol] 210 | ``` 211 | 212 | The symbol must exist, or the test will fail. 213 | 214 | The format of the symbol file looks like this: 215 | 216 | ``` 217 | .label ENABLE=$80 218 | .label DISABLE=$00 219 | .label TIMER_ONE_SECOND=$3c 220 | .label TIMER_SINGLE=$0 221 | .label TIMER_STRUCT_BYTES=$40 222 | 223 | .label UpdateTimers=$209d 224 | .label UpdateScreen=$21cc 225 | 226 | .label c64lib_timers=$33c 227 | ``` 228 | 229 | The CLI also supports symbol files containing namespaces: 230 | 231 | ``` 232 | .namespace vic { 233 | .label SP0X = $d000 234 | .label SP0Y = $d001 235 | .label SP1X = $d002 236 | .label SP1Y = $d003 237 | .label SP2X = $d004 238 | .label SP2Y = $d005 239 | .label SP3X = $d006 240 | .label SP3Y = $d007 241 | .label SP4X = $d008 242 | .label SP4Y = $d009 243 | .label SP5X = $d00a 244 | .label SP5Y = $d00b 245 | .label SP6X = $d00c 246 | .label SP6Y = $d00d 247 | .label SP7X = $d00e 248 | .label SP7Y = $d00f 249 | } 250 | ``` 251 | 252 | If you wanted to reference the symbol `SP0X` inside of the `vic` namespace, you'd reference it as `[vic.SP0X]`. 253 | 254 | You can also perform simple expressions like `[UpdateTimers] + 1` or `peekword([r0L])`. 255 | 256 | 257 | #### What's missing? 258 | 259 | There is absolutely no concept of hardware other than the 6502. There's no VIC, SID, CIA, etc, so testing against programs that use these hardware devices is pretty limited. You CAN, and the `example` test suite shows this, test to make sure sprite registers are set properly since it's just memory. 260 | 261 | This is a vanilla 6502 with no concept of any C64 specific hardware. I would LOVE to have a full c64 simulator, but that's not where we are right now. 262 | 263 | #### Thanks 264 | 265 | Thanks to Aaron Mell for building the 6502 simulator (https://github.com/aaronmell/6502Net). It was a tremendous help in building this tool. 266 | 267 | Thanks to Terence Parr and Sam Harwell for ANTLR. (https://www.antlr.org/) 268 | 269 | #### License 270 | 271 | ANTLR 4.8 is Copyright (C) 2012 Terence Parr and Sam Harwell. All Rights Reserved. 272 | 273 | The 6502 Simulator and associated test suite are Copyright (C) 2013 by Aaron Mell. All Rights Reserved. 274 | 275 | The 6502 Unit Test CLI and associated test suite are Copyright (C) 2020 by Barry Walker. All Rights Reserved. 276 | 277 | 278 | Redistribution and use in source and binary forms, with or without 279 | modification, are permitted provided that the following conditions are met: 280 | 281 | 1. Redistributions of source code must retain the above copyright notice, this 282 | list of conditions and the following disclaimer. 283 | 2. Redistributions in binary form must reproduce the above copyright notice, 284 | this list of conditions and the following disclaimer in the documentation 285 | and/or other materials provided with the distribution. 286 | 287 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 288 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 289 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 290 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 291 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 292 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 293 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 294 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 295 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 296 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 297 | 298 | -------------------------------------------------------------------------------- /dependencies/NCalc.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryw/sim6502/cdc88363904d14c1292ab5cdcf013fa68fe7c41d/dependencies/NCalc.dll -------------------------------------------------------------------------------- /dependencies/NCalc.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryw/sim6502/cdc88363904d14c1292ab5cdcf013fa68fe7c41d/dependencies/NCalc.pdb -------------------------------------------------------------------------------- /dependencies/antlr-4.8-complete.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryw/sim6502/cdc88363904d14c1292ab5cdcf013fa68fe7c41d/dependencies/antlr-4.8-complete.jar -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | docker pull barrywalker71/sim6502cli:latest 3 | docker run -v ${PWD}:/code -it barrywalker71/sim6502cli:latest -s /code/tests.6502 4 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | __ _____ ___ ___ _ _ _ _ _______ _ _____ _ _____ 2 | / /| ____|/ _ \__ \ | | | | (_) | |__ __| | | / ____| | |_ _| 3 | / /_| |__ | | | | ) | | | | |_ __ _| |_ | | ___ ___| |_ | | | | | | 4 | | '_ \___ \| | | |/ / | | | | '_ \| | __| | |/ _ \/ __| __| | | | | | | 5 | | (_) |__) | |_| / /_ | |__| | | | | | |_ | | __/\__ \ |_ | |____| |____ _| |_ 6 | \___/____/ \___/____| \____/|_| |_|_|\__| |_|\___||___/\__| \_____|______|_____| 7 | 8 | c64lib examples 9 | 10 | #### Introduction 11 | 12 | This directory contains a decent sized test suite on my c64lib project (https://github.com/barryw/c64lib). This library is a suite of functions for sprites, timers, memory management, joystick/keyboard reading, etc. 13 | 14 | The 6502 Unit Test CLI is run as a Docker container, so you will need to have Docker running. 15 | 16 | Run the tests by running `make` in this directory. The test definitions are in `tests.6502` and the code under test is `include_me_full.prg` 17 | -------------------------------------------------------------------------------- /example/include_me_full.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryw/sim6502/cdc88363904d14c1292ab5cdcf013fa68fe7c41d/example/include_me_full.prg -------------------------------------------------------------------------------- /example/include_me_full.sym: -------------------------------------------------------------------------------- 1 | .label r2=$61 2 | .label r3=$63 3 | .label r4=$65 4 | .label r5=$67 5 | .label r6=$69 6 | .label r7=$6b 7 | .label r4H=$66 8 | .label r0H=$fc 9 | .label r4L=$65 10 | .label TIMER_ONE_SECOND=$3c 11 | .label SPR_NORMAL=$0 12 | .label r0L=$fb 13 | .label SPR_MULTICOLOR=$80 14 | .label JOY_DOWN=$2 15 | .namespace vic { 16 | .label EXTCOL=$d020 17 | .label SP3X=$d006 18 | .label SP3Y=$d007 19 | .label SP7COL=$d02e 20 | .label SP3COL=$d02a 21 | .label SPENA=$d015 22 | .label ScreenMemoryBase=$206f 23 | .label DEFAULT_SCREEN_BASE=$400 24 | .label SPMC=$d01c 25 | .label LPENY=$d014 26 | .label SCREEN_MEM_POINTER_MASK=$f0 27 | .label LPENX=$d013 28 | .label SCROLX=$d016 29 | .label SP2Y=$d005 30 | .label SCROLY=$d011 31 | .label CharacterMemoryBase=$2073 32 | .label SP2X=$d004 33 | .label SP6Y=$d00d 34 | .label IRQMSK=$d01a 35 | .label SP4COL=$d02b 36 | .label SP0COL=$d027 37 | .label DEFAULT_VIC_BANK=$0 38 | .label BGCOL3=$d024 39 | .label SpritePointerBase=$2071 40 | .label BankMemoryBase=$206d 41 | .label SP7X=$d00e 42 | .label SP7Y=$d00f 43 | .label DEFAULT_SPRITE_POINTER_BASE=$7f8 44 | .label VICIRQ=$d019 45 | .label BGCOL0=$d021 46 | .label DEFAULT_CHAR_BASE=$1000 47 | .label BGCOL1=$d022 48 | .label BGCOL2=$d023 49 | .label XXPAND=$d01d 50 | .label SP1X=$d002 51 | .label SP1Y=$d003 52 | .label SP5X=$d00a 53 | .label SP5Y=$d00b 54 | .label SCREEN_MEM_REV_POINTER_MASK=$f 55 | .label SP5COL=$d02c 56 | .label SPBGPR=$d01b 57 | .label SP1COL=$d028 58 | .label SPSPCL=$d01e 59 | .label RASTER=$d012 60 | .label SP6X=$d00c 61 | .label YXPAND=$d017 62 | .label SP0Y=$d001 63 | .label SP0X=$d000 64 | .label SPBGCL=$d01f 65 | .label SP4Y=$d009 66 | .label VMCSB=$d018 67 | .label SP6COL=$d02d 68 | .label SP4X=$d008 69 | .label SPMC1=$d026 70 | .label SPMC0=$d025 71 | .label SP2COL=$d029 72 | .label CHAR_MEM_POINTER_MASK=$e 73 | .label COLCLK=$d81a 74 | .label MSIGX=$d010 75 | .label CHAR_MEM_REV_POINTER_MASK=$f1 76 | } 77 | .label SPR_HIDE=$0 78 | .label c64lib_joy_left=$73 79 | .label CopyMemory=$21b8 80 | .label TIMER_FOUR_SECONDS=$f0 81 | .label SPR_VISIBLE=$15 82 | .namespace kernal { 83 | .label VEC_SAVE=$ffd8 84 | .label VEC_STOP=$ffe1 85 | .label ILOAD=$330 86 | .label RND=$e097 87 | .label CLOSE=$e1c7 88 | .label VEC_SETTMO=$ffa2 89 | .label VEC_SECOND=$ff93 90 | .label RADDC=$e092 91 | .label IRQVEC=$314 92 | .label VEC_SETMSG=$ff90 93 | .label VEC_TKSA=$ff96 94 | .label IBASIN=$324 95 | .label VEC_CIOUT=$ffa8 96 | .label VEC_UDTIM=$ffea 97 | .label VEC_IOBASE=$fff3 98 | .label IGETIN=$32a 99 | .label ICLALL=$32c 100 | .label VEC_LISTEN=$ffb1 101 | .label VEC_PLOT=$fff0 102 | .label SYS=$e12a 103 | .label VEC_CLOSE=$ffc3 104 | .label VEC_CLRCHN=$ffcc 105 | .label VEC_MEMBOT=$ff99 106 | .label CINV=$314 107 | .label VEC_SETNAM=$ffbd 108 | .label VEC_CLALL=$ffe7 109 | .label VEC_SETTIM=$ffdb 110 | .label VEC_LOAD=$ffd5 111 | .label VEC_CHRIN=$ffcf 112 | .label IOPEN=$31a 113 | .label VEC_UNLSN=$ffae 114 | .label VEC_RESTOR=$ff8a 115 | .label VEC_CHROUT=$ffd2 116 | .label FREE1=$334 117 | .label LOAD=$e168 118 | .label VEC_GETIN=$ffe4 119 | .label FREE2=$3fc 120 | .label VEC_VECTOR=$ff8d 121 | .label ICLOSE=$31c 122 | .label VERIFY=$e165 123 | .label IBSOUT=$326 124 | .label VEC_SETLFS=$ffba 125 | .label VEC_RAMTAS=$ff87 126 | .label VEC_UNTLK=$ffab 127 | .label IRQNOR=$ea31 128 | .label VEC_OPEN=$ffc0 129 | .label VEC_RDTIM=$ffde 130 | .label RMULC=$e08d 131 | .label VEC_MEMTOP=$ff9c 132 | .label SAVE=$e156 133 | .label CBINV=$316 134 | .label NMINV=$318 135 | .label VEC_ACPTR=$ffa5 136 | .label VEC_SCNKEY=$ff9f 137 | .label ICLRCH=$322 138 | .label ISTOP=$328 139 | .label ICHKIN=$31e 140 | .label VEC_SCREEN=$ffed 141 | .label USRCMD=$32e 142 | .label LSTX=$c5 143 | .label POLY1=$e043 144 | .label POLY2=$e059 145 | .label VEC_IOINIT=$ff84 146 | .label ISAVE=$332 147 | .label TBUFFER=$33c 148 | .label OPEN=$e1be 149 | .label CLRSCR=$e544 150 | .label VEC_CINT=$ff81 151 | .label VEC_READST=$ffb7 152 | .label ICKOUT=$320 153 | .label VEC_CHKOUT=$ffc9 154 | .label HOME=$e566 155 | .label VEC_TALK=$ffb4 156 | .label VEC_CHKIN=$ffc6 157 | } 158 | .label SPR_FG=$0 159 | .label JOY_BUTTON=$10 160 | .label SPR_BG=$80 161 | .label JOY_RIGHT=$8 162 | .label DISABLE=$0 163 | .label BANK=$0 164 | .label r5H=$68 165 | .label SPR_PRIORITY=$1b 166 | .label SPR_SHOW=$80 167 | .label BitMaskPow2=$20c3 168 | .label r1H=$fe 169 | .label r5L=$67 170 | .label TRUE=$80 171 | .label ENABLE=$80 172 | .label r1L=$fd 173 | .label BankLookup=$2069 174 | .label ReadJoystick=$2245 175 | .label SPR_HIRES=$0 176 | .namespace cia { 177 | .label CIACRA=$dc0e 178 | .label CI2PRA=$dd00 179 | .label BANK_1_MASK=$2 180 | .label CIAICR=$dc0d 181 | .label CI2PRB=$dd01 182 | .label VIC_BANK_REVERSE_MASK=$fc 183 | .label C2DDRB=$dd03 184 | .label C2DDRA=$dd02 185 | .label TO2TEN=$dd08 186 | .label CIACRB=$dc0f 187 | .label TODHRS=$dc0b 188 | .label CI2CRB=$dd0f 189 | .label CI2CRA=$dd0e 190 | .label BANK_3_MASK=$0 191 | .label VIC_BANK_MASK=$3 192 | .label TO2HRS=$dd0b 193 | .label BANK_0_MASK=$3 194 | .label CI2ICR=$dd0d 195 | .label CIASDR=$dc0c 196 | .label TODTEN=$dc08 197 | .label CI2SDR=$dd0c 198 | .label CIDDRA=$dc02 199 | .label CIDDRB=$dc03 200 | .label BANK_2_MASK=$1 201 | .label TIMBLO=$dc06 202 | .label TO2SEC=$dd09 203 | .label TIMALO=$dc04 204 | .label TO2MIN=$dd0a 205 | .label TIMBHI=$dc07 206 | .label TI2ALO=$dd04 207 | .label TIMAHI=$dc05 208 | .label TI2BHI=$dd07 209 | .label TI2AHI=$dd05 210 | .label TODSEC=$dc09 211 | .label TODMIN=$dc0a 212 | .label TI2BLO=$dd06 213 | .label CIAPRA=$dc00 214 | .label CIAPRB=$dc01 215 | } 216 | .namespace basic { 217 | .label PRINT=$aaa0 218 | .label TOK_POS=$b9 219 | .label TOK_LIST=$9b 220 | .label FDCEND=$bf3a 221 | .label GETSTK=$a3fb 222 | .label DORE1=$b016 223 | .label ERROR=$a437 224 | .label FRMEVAL=$ad9e 225 | .label TOK_STR=$c4 226 | .label CHKOPN=$aefa 227 | .label MOV2F=$bbc7 228 | .label EXIGNT=$acfc 229 | .label QPLOP=$a717 230 | .label GOSUB=$a883 231 | .label POS=$b39e 232 | .label TOK_SUB=$ab 233 | .label TOK_STEP=$a9 234 | .label TOK_TO=$a4 235 | .label DATAN=$a906 236 | .label TOK_VERIFY=$95 237 | .label FSUB=$b850 238 | .label TOK_MID=$ca 239 | .label TOK_DIV=$ad 240 | .label PRINTN=$aa80 241 | .label TOK_ATN=$c1 242 | .label FDIV=$bb0f 243 | .label TOK_REM=$8f 244 | .label TOK_SGN=$b4 245 | .label ASC=$b78b 246 | .label ABS=$bc58 247 | .label BLTU=$a3b8 248 | .label TOK_ADD=$aa 249 | .label DOAGIN=$ab4d 250 | .label PARCHK=$aef1 251 | .label TOK_CHR=$c7 252 | .label FADD=$b867 253 | .label MULSHF=$b983 254 | .label TOK_CLOSE=$a0 255 | .label ANDOP=$afe9 256 | .label FONE=$b9bc 257 | .label TOK_ABS=$b6 258 | .label TOK_ASC=$c6 259 | .label DIM=$b018 260 | .label RUN=$a871 261 | .label FRESTR=$b6a3 262 | .label STMDSP=$a00c 263 | .label STRD=$b465 264 | .label ARYGET=$b194 265 | .label ERRTAB=$a19e 266 | .label TOK_RUN=$8a 267 | .label REM=$a93b 268 | .label MULDIV=$bab7 269 | .label MOVAF=$bc0c 270 | .label SGN=$bc39 271 | .label TOK_DIM=$86 272 | .label NEGFAC=$b947 273 | .label TOK_OR=$b0 274 | .label TOK_SQR=$ba 275 | .label GETADR=$b7f7 276 | .label FHALF=$bf11 277 | .label FOUTBL=$bf1c 278 | .label FUWAIT=$b82d 279 | .label TOK_AND=$af 280 | .label FCERR=$b248 281 | .label MLTPLY=$ba59 282 | .label GETFNM=$b3e1 283 | .label TOK_MULT=$ac 284 | .label BSERR=$b245 285 | .label TOK_ON=$91 286 | .label FNDOER=$b3f4 287 | .label TOK_RETURN=$8e 288 | .label FINPTR=$b185 289 | .label TOK_CONT=$9a 290 | .label MUL10=$bae2 291 | .label FOR=$a742 292 | .label CHKCLS=$aef7 293 | .label CRUNCH=$a579 294 | .label STRLIT=$b487 295 | .label FDIVT=$bb12 296 | .label END=$a831 297 | .label EVAL=$ae83 298 | .label CONUPK=$ba8c 299 | .label LIST=$a69c 300 | .label GONE=$a7e4 301 | .label FADDT=$b86a 302 | .label TOK_LEN=$c3 303 | .label FINLOG=$bd7e 304 | .label TOK_EXP=$bd 305 | .label TOK_LET=$88 306 | .label RESLST=$a09e 307 | .label MOVFA=$bbfc 308 | .label RETURN=$a8d2 309 | .label GARBAG=$b526 310 | .label FADDH=$b849 311 | .label NEXT=$ad1e 312 | .label TOK_RESTORE=$8c 313 | .label MOVFM=$bba2 314 | .label OMERR=$a435 315 | .label TOK_LOAD=$93 316 | .label FRMNUM=$ad8a 317 | .label FADD4=$b8a7 318 | .label PIVAL=$aea8 319 | .label PTRGET=$b08b 320 | .label INPUTN=$aba5 321 | .label TOK_GOSUB=$8d 322 | .label TOK_INT=$b5 323 | .label TOK_NEXT=$82 324 | .label N32768=$b1a5 325 | .label TOK_DEF=$96 326 | .label ISARY=$b1d1 327 | .label MOVEF=$bc0f 328 | .label FRE=$b37d 329 | .label ONGOTO=$a94b 330 | .label LINGET=$a96b 331 | .label EXPCON=$bfbf 332 | .label TOK_GET=$a1 333 | .label VAL=$b7ad 334 | .label TOK_POKE=$97 335 | .label INLIN=$a560 336 | .label FOUT=$bddd 337 | .label TOK_RIGHT=$c9 338 | .label TOK_READ=$87 339 | .label SCRTCH=$a642 340 | .label LINKPRG=$a533 341 | .label STROUT=$ab1e 342 | .label CMD=$aa86 343 | .label TOK_DATA=$83 344 | .label IF=$a928 345 | .label RUNC=$a68e 346 | .label READY=$a474 347 | .label OROP=$afe6 348 | .label TOK_LT=$b3 349 | .label LOG=$b9ea 350 | .label AYINT=$b1bf 351 | .label TOK_CMD=$9d 352 | .label CONT=$a857 353 | .label TOK_LOG=$bc 354 | .label GET=$ab7b 355 | .label MIDD=$b737 356 | .label NEGOP=$bfb4 357 | .label TOK_PEEK=$c2 358 | .label TOK_TAB=$a3 359 | .label TOK_USR=$b7 360 | .label GOTO=$a8a0 361 | .label CHRD=$b6ec 362 | .label TOK_SPC=$a6 363 | .label MLDVEX=$bad4 364 | .label LEFTD=$b700 365 | .label TOK_GOTO=$89 366 | .label TOK_TAN=$c0 367 | .label TOK_NEW=$a2 368 | .label RESTOR=$a81d 369 | .label LINPRT=$bdcd 370 | .label TOK_RND=$bb 371 | .label TOK_IF=$8b 372 | .label ERRDIR=$b3a6 373 | .label NOTFNS=$b11d 374 | .label PREAM=$b761 375 | .label INPRT=$bdc0 376 | .label TOK_SAVE=$94 377 | .label FINDLN=$a613 378 | .label TOK_WAIT=$92 379 | .label INTIDX=$b1b2 380 | .label GETBYTC=$b79b 381 | .label GETNUM=$b7eb 382 | .label CBMBASIC=$a004 383 | .label TOK_INPUTN=$84 384 | .label TOK_INPUT=$85 385 | .label FNDFOR=$a38a 386 | .label CHKCOM=$aeff 387 | .label FRETMS=$b6db 388 | .label FSUBT=$b853 389 | .label PEEK=$b80d 390 | .label NORMAL=$b8fe 391 | .label TOK_COS=$be 392 | .label OVERR=$b97e 393 | .label TOK_THEN=$a7 394 | .label TOK_NOT=$a8 395 | .label INPUT=$abbf 396 | .label FMULT=$ba28 397 | .label OPTAB=$a080 398 | .label TOK_END=$80 399 | .label TOK_SIN=$bf 400 | .label GIVAYF=$b391 401 | .label TOK_GT=$b1 402 | .label GETSPA=$b4f4 403 | .label TOK_PRINTN=$98 404 | .label MAIN=$a480 405 | .label SIGN=$bc2b 406 | .label REASON=$a408 407 | .label NEWSTT=$a7ae 408 | .label LOGCN2=$b9c1 409 | .label FCOMP=$bc5b 410 | .label TOK_PRINT=$99 411 | .label READ=$ac06 412 | .label DIV10=$bafe 413 | .label TOK_OPEN=$9f 414 | .label DATA=$a8f8 415 | .label SQR=$bf71 416 | .label ISVAR=$af2b 417 | .label CAT=$b63d 418 | .label TOK_SYS=$9e 419 | .label SNERR=$af08 420 | .label MOVINS=$b67a 421 | .label POKE=$b824 422 | .label TOK_FOR=$81 423 | .label TENC=$baf9 424 | .label MAIN1=$a49c 425 | .label ROUND=$bc1b 426 | .label TOK_EQ=$b2 427 | .label TOK_FRE=$b8 428 | .label INT=$bccc 429 | .label FPWRT=$bf7b 430 | .label TOK_VAL=$c5 431 | .label UMULT=$b34c 432 | .label NO999=$bdb3 433 | .label RIGHTD=$b72c 434 | .label TOK_CLR=$9c 435 | .label ISFUN=$afa7 436 | .label TOK_FN=$a5 437 | .label DEF=$b3b3 438 | .label TOK_EXPN=$ae 439 | .label FIN=$bcf3 440 | .label LEN=$b77c 441 | .label LET=$a9a5 442 | .label QINT=$bc9b 443 | .label EXP=$bfed 444 | .label TOK_STOP=$90 445 | .label TOK_LEFT=$c8 446 | .label CLEAR=$a65e 447 | } 448 | .label TIMER_HALF_SECOND=$1e 449 | .label TIMER_THREE_SECONDS=$b4 450 | .label EnDisTimer=$2189 451 | .label UpdateTimers=$2112 452 | .label TIMER_SINGLE=$0 453 | .label SPR_X_EXPAND=$1d 454 | .label r6H=$6a 455 | .label ChangeSpriteAttribute=$20a7 456 | .label r2H=$62 457 | .label r6L=$69 458 | .label PositionSprite=$2075 459 | .label r2L=$61 460 | .namespace sid { 461 | .label ATDCY1=$d405 462 | .label ATDCY2=$d40c 463 | .label ATDCY3=$d413 464 | .label SUREL3=$d414 465 | .label SUREL1=$d406 466 | .label SUREL2=$d40d 467 | .label FREHI1=$d401 468 | .label FRELO3=$d40e 469 | .label FRELO2=$d407 470 | .label POTY=$d41a 471 | .label FRELO1=$d400 472 | .label PWHI3=$d411 473 | .label PWHI2=$d40a 474 | .label PWHI1=$d403 475 | .label POTX=$d419 476 | .label RANDOM=$d41b 477 | .label ENV3=$d41c 478 | .label SIGVOL=$d418 479 | .label FREHI3=$d40f 480 | .label FREHI2=$d408 481 | .label PWLO1=$d402 482 | .label PWLO2=$d409 483 | .label PWLO3=$d410 484 | .label VCREG3=$d412 485 | .label CUTHI=$d416 486 | .label RESON=$d417 487 | .label VCREG2=$d40b 488 | .label VCREG1=$d404 489 | .label CUTLO=$d415 490 | } 491 | .label JOY_UP=$1 492 | .label JOY_LEFT=$4 493 | .label ReadJoysticks=$223b 494 | .label TIMER_TWO_SECONDS=$78 495 | .label TIMER_CONTINUOUS=$1 496 | .label CreateTimer=$20e3 497 | .label c64lib_joy_btn=$6d 498 | .label SPR_Y_EXPAND=$17 499 | .label SetVICBank=$2000 500 | .label ClearTimers=$20cb { 501 | } 502 | .label c64lib_timers=$33c 503 | .label r7H=$6c 504 | .label r3H=$64 505 | .label r7L=$6b 506 | .label Keyboard=$228c { 507 | .label Buffer=$248d 508 | .label TooManyNewKeys=$243e 509 | .label Return=$2429 510 | .label BufferQuantity=$2491 511 | .label SimultaneousAlphanumericKeysFlag=$2492 512 | .label KeyInRow=$228f 513 | .label NoActivityDetected=$22df 514 | .label BufferEmpty=$2427 515 | .label Exist=$240a 516 | .label KeyFound=$22c7 517 | .label ControlPort=$22f1 518 | .label KeyTable=$244a 519 | .label BufferOld=$248a 520 | .label Main=$22f5 521 | .label OverFlow=$22d7 522 | } 523 | .label r3L=$63 524 | .label FillMemory=$2195 525 | .label SPR_HMC=$1c 526 | .label UpdateBaseLocations=$2037 527 | .label FALSE=$0 528 | .label VIC_START=$0 529 | .label SPR_EXPAND=$80 530 | .label TIMER_STRUCT_BYTES=$40 531 | .label c64lib_joy_right=$75 532 | .label r0=$fb 533 | .label c64lib_joy_up=$6f 534 | .label c64lib_joy_down=$71 535 | .label r1=$fd 536 | -------------------------------------------------------------------------------- /example/tests.6502: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Tests against pseudo register library") { 3 | ; Load the program under test 4 | symbols("/code/include_me_full.sym") 5 | load("/code/include_me_full.prg", strip_header = true) 6 | 7 | test("memory-fill-1", "Fill an uneven block of memory") { 8 | [r0L] = $bd ; Stuff $bd into our memory locations. Odd number, right? 9 | [r1] = $1234 ; Start at $1234 10 | [r2] = $12c ; and do 300 bytes 11 | 12 | jsr([FillMemory], stop_on_rts = true, fail_on_brk = true) 13 | 14 | assert(cycles < 11541, "We can fill this block in fewer than 11541 cycles") 15 | assert(memchk($1234, $12c, $bd), "Memory was filled properly") 16 | } 17 | 18 | test("memory-copy-1", "Ensure memory copy works") { 19 | [r0] = $e000 ; Copy the KERNAL rom 20 | [r1] = $4000 ; into $4000 21 | [r2] = $2000 ; Copy all 8k of it 22 | 23 | jsr([CopyMemory], stop_on_rts = true, fail_on_brk = true) 24 | 25 | assert(cycles < 131720, "Ensure that we run in fewer than 131720 cycles") 26 | assert(memcmp($e000, $4000, $2000), "Ensure that KERNAL was copied correctly") 27 | } 28 | 29 | test("sprites-enable-x-expand-correctly", "Enable horizontal expansion of a sprite") { 30 | [r3L] = $01 31 | [r3H] = [SPR_X_EXPAND] 32 | [r4L] = [SPR_EXPAND] 33 | [vic.XXPAND] = $80 34 | 35 | jsr([ChangeSpriteAttribute], stop_on_rts = true, fail_on_brk = true) 36 | 37 | assert(cycles < 34, "Ensure that we run in fewer than 34 cycles") 38 | assert([vic.XXPAND] == $82, "Sprite 1's horizontal expansion is set to True") 39 | } 40 | 41 | test("sprites-disable-x-expand-correctly", "Disable horizontal expansion of a sprite") { 42 | [r3L] = $05 43 | [r3H] = [SPR_X_EXPAND] 44 | [r4L] = [SPR_NORMAL] 45 | [vic.XXPAND] = $60 46 | 47 | jsr([ChangeSpriteAttribute], stop_on_rts = true, fail_on_brk = true) 48 | 49 | assert(cycles < 38, "Ensure that we run in fewer than 38 cycles") 50 | assert([vic.XXPAND] == $40, "Sprite 5's horizontal expansion is set to False") 51 | } 52 | 53 | test("sprites-enable-sprite-correctly", "Enable a sprite") { 54 | [r3L] = $07 55 | [r3H] = [SPR_VISIBLE] 56 | [r4L] = [SPR_SHOW] 57 | [vic.SPENA] = $01 58 | 59 | jsr([ChangeSpriteAttribute], stop_on_rts = true, fail_on_brk = true) 60 | 61 | assert(cycles < 34, "Ensure that we run in fewer than 34 cycles") 62 | assert([vic.SPENA] == $81, "Sprite 7 and 0 are now enabled") 63 | } 64 | 65 | test("sprites-disable-sprite-correctly", "Disable a sprite") { 66 | [r3L] = $03 67 | [r3H] = [SPR_VISIBLE] 68 | [r4L] = [SPR_HIDE] 69 | [vic.SPENA] = $0a 70 | 71 | jsr([ChangeSpriteAttribute], stop_on_rts = true, fail_on_brk = true) 72 | 73 | assert(cycles < 38, "Ensure that we run in fewer than 38 cycles") 74 | assert([vic.SPENA] == $02, "Sprite 3 is disabled and sprite 1 is still enabled") 75 | } 76 | 77 | test("sprites-positions-correctly-without-msb", "Sprite X pos < 256 sets MSB to 0") { 78 | [vic.MSIGX] = $00 79 | [r3L] = $00 80 | [r4] = $00ff 81 | [r5L] = $40 82 | 83 | jsr([PositionSprite], stop_on_rts = true, fail_on_brk = true) 84 | 85 | assert(cycles < 71, "Ensure that we run in fewer than 71 cycles") 86 | assert([vic.SP0X] == $ff, "Sprite 0's X pos is at ff") 87 | assert([vic.MSIGX] == $00, "And sprite 0's MSB is set to 0") 88 | } 89 | 90 | test("sprites-sets-msb-properly", "Moving a sprite horizontally sets the MSB properly") { 91 | [vic.MSIGX] = $00 92 | [r3L] = $00 93 | [r4] = $0100 94 | [r5] = $40 95 | 96 | jsr([PositionSprite], stop_on_rts = true, fail_on_brk = true) 97 | 98 | assert(cycles < 78, "Ensure that we run in fewer than 78 cycles") 99 | assert([vic.SP0X] == $00, "Sprite 0's X pos is at 0") 100 | assert([vic.MSIGX] == $01, "But sprite 0's MSB is set to 1") 101 | } 102 | 103 | test("timer-single-disables-on-update", "Single shot timer disables when it hits 0") { 104 | [c64lib_timers] = [ENABLE] ; Enable timer 0 105 | [c64lib_timers] + $01 = [TIMER_SINGLE] ; It's a single shot timer 106 | [c64lib_timers] + $02 = $01 ; Current countdown has 1 tick left 107 | [c64lib_timers] + $04 = [TIMER_ONE_SECOND] ; Fires every second 108 | [c64lib_timers] + $06 = [ReadJoysticks] ; Calls the routine to read the joysticks when it fires 109 | 110 | jsr([UpdateTimers], stop_on_rts = true, fail_on_brk = true) 111 | 112 | assert(cycles < 471, "Ensure that we run in fewer than 471 cycles") 113 | assert([c64lib_timers] == [DISABLE], "Timer is disabled") 114 | } 115 | 116 | test("timer-continuous-will-reset-on-update", "Continuous timer resets when it hits 0") { 117 | [c64lib_timers] = [ENABLE] 118 | [c64lib_timers] + $01 = [TIMER_CONTINUOUS] 119 | [c64lib_timers] + $02 = $01 120 | [c64lib_timers] + $04 = [TIMER_ONE_SECOND] 121 | [c64lib_timers] + $06 = [ReadJoysticks] 122 | 123 | jsr([UpdateTimers], stop_on_rts = true, fail_on_brk = true) 124 | 125 | assert(cycles < 462, "Ensure that we run in fewer than 462 cycles") 126 | assert([c64lib_timers] == [ENABLE], "Timer is enabled") 127 | assert([c64lib_timers] + $02 == [TIMER_ONE_SECOND], "Current value has been reset") 128 | } 129 | 130 | test("timer-enable", "Enable a disabled timer") { 131 | [c64lib_timers] = [DISABLE] 132 | [r2H] = $00 133 | [r3L] = [ENABLE] 134 | 135 | jsr([EnDisTimer], stop_on_rts = true, fail_on_brk = true) 136 | 137 | assert(cycles < 26, "Ensure that we run in fewer than 26 cycles") 138 | assert([c64lib_timers] == [ENABLE], "Timer has been enabled") 139 | } 140 | 141 | test("timer-disable", "Disable an enabled timer") { 142 | [c64lib_timers] = [ENABLE] 143 | [r2H] = $00 144 | [r3L] = [DISABLE] 145 | 146 | jsr([EnDisTimer], stop_on_rts = true, fail_on_brk = true) 147 | 148 | assert(cycles < 26, "Ensure that we run in fewer than 26 cycles") 149 | assert([c64lib_timers] == [DISABLE], "Timer has been enabled") 150 | } 151 | 152 | test("timer-init-timer-memory", "Make sure initializing the timers clears timer memory") { 153 | jsr([ClearTimers], stop_on_rts = true, fail_on_brk = true) 154 | 155 | assert(cycles < 2538, "Ensure that we run in fewer than 2538 cycles") 156 | assert(memchk([c64lib_timers], [TIMER_STRUCT_BYTES], $00), "Timer memory is cleared") 157 | } 158 | 159 | test("timer-create-single-shot", "Make sure we can create a single shot timer") { 160 | [r0] = $1000 161 | [r1] = [ReadJoysticks] 162 | [r2L] = [TIMER_SINGLE] 163 | [r2H] = $00 164 | [r3L] = [ENABLE] 165 | 166 | jsr([CreateTimer], stop_on_rts = true, fail_on_brk = true) 167 | 168 | assert(cycles < 82, "Ensure that we run in fewer than 82 cycles") 169 | assert([c64lib_timers] + $00 + peekbyte([r2H]) * 8 == [ENABLE], "Timer enabled") 170 | assert([c64lib_timers] + $01 + peekbyte([r2H]) * 8 == [TIMER_SINGLE], "Timer type is single") 171 | assert(([c64lib_timers] + $02 + peekbyte([r2H]) * 8).w == $1000, "Timer's current value") 172 | assert(([c64lib_timers] + $04 + peekbyte([r2H]) * 8).w == $1000, "Timer's frequency") 173 | assert(([c64lib_timers] + $06 + peekbyte([r2H]) * 8).w == [ReadJoysticks], "Timer's callback address") 174 | } 175 | 176 | test("vic-set-bank-chars-and-screen-i", "Set VIC bank to 0, screen to 1024 and chars to 12288") { 177 | [r0L] = $00 178 | [r0H] = $06 179 | [r1L] = $01 180 | 181 | jsr([SetVICBank], stop_on_rts = true, fail_on_brk = true) 182 | 183 | assert(cycles < 163, "Ensure that we run in fewer than 163 cycles") 184 | assert([cia.CI2PRA] == $03, "CIA 2 is set properly") 185 | assert([vic.VMCSB] == $1c, "VIC is set properly") 186 | assert([vic.BankMemoryBase].w == $0000, "Bank Memory Base is set properly") 187 | assert([vic.ScreenMemoryBase].w == $0400, "Screen Memory Base is set properly") 188 | assert([vic.CharacterMemoryBase].w == $3000, "Character Memory Base is set properly") 189 | assert([vic.SpritePointerBase].w == $07f8, "Sprite Pointer Base is set properly") 190 | } 191 | 192 | test("vic-set-bank-chars-and-screen-ii", "Set VIC bank to 3, screen to 4096 and chars to 8192") { 193 | [r0L] = $03 194 | [r0H] = $04 195 | [r1L] = $04 196 | 197 | jsr([SetVICBank], stop_on_rts = true, fail_on_brk = true) 198 | 199 | assert(cycles < 163, "Ensure that we run in fewer than 163 cycles") 200 | assert([cia.CI2PRA] == $00, "CIA 2 is set properly") 201 | assert([vic.VMCSB] == $48, "VIC is set properly") 202 | assert([vic.BankMemoryBase].w == $c000, "Bank Memory Base is set properly") 203 | assert([vic.ScreenMemoryBase].w == $d000, "Screen Memory Base is set properly") 204 | assert([vic.CharacterMemoryBase].w == $e000, "Character Memory Base is set properly") 205 | assert([vic.SpritePointerBase].w == $d3f8, "Sprite Pointer Base is set properly") 206 | } 207 | 208 | test("vic-set-bank-chars-and-screen-iii", "Set VIC bank to 2, screen to 8192 and chars to 0") { 209 | [r0L] = $02 210 | [r0H] = $00 211 | [r1L] = $08 212 | 213 | jsr([SetVICBank], stop_on_rts = true, fail_on_brk = true) 214 | 215 | assert(cycles <= 162, "Ensure that we run in fewer than 163 cycles") 216 | assert([cia.CI2PRA] == $01, "CIA 2 is set properly") 217 | assert([vic.VMCSB] == $80, "VIC is set properly") 218 | assert([vic.BankMemoryBase].w == $8000, "Bank Memory Base is set properly") 219 | assert([vic.ScreenMemoryBase].w == $a000, "Screen Memory Base is set properly") 220 | assert([vic.CharacterMemoryBase].w == $8000, "Character Memory Base is set properly") 221 | assert([vic.SpritePointerBase].w == $a3f8, "Sprite Pointer Base is set properly") 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /sim6502.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sim6502", "sim6502\sim6502.csproj", "{48BBDA55-276F-4FA3-8D3E-C798630D725A}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sim6502tests", "sim6502tests\sim6502tests.csproj", "{D18CFE0E-7F1F-46B7-9BB2-5B1967C9EEBC}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {48BBDA55-276F-4FA3-8D3E-C798630D725A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {48BBDA55-276F-4FA3-8D3E-C798630D725A}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {48BBDA55-276F-4FA3-8D3E-C798630D725A}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {48BBDA55-276F-4FA3-8D3E-C798630D725A}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {D18CFE0E-7F1F-46B7-9BB2-5B1967C9EEBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {D18CFE0E-7F1F-46B7-9BB2-5B1967C9EEBC}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {D18CFE0E-7F1F-46B7-9BB2-5B1967C9EEBC}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {D18CFE0E-7F1F-46B7-9BB2-5B1967C9EEBC}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /sim6502.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True 6 | True 7 | True 8 | 9 | True 10 | True 11 | True 12 | True 13 | True 14 | True 15 | True 16 | True 17 | True 18 | True 19 | True 20 | True 21 | True 22 | True 23 | True 24 | True 25 | True -------------------------------------------------------------------------------- /sim6502/Expressions/BaseCompare.cs: -------------------------------------------------------------------------------- 1 | using sim6502.Proc; 2 | 3 | namespace sim6502.Expressions 4 | { 5 | public class BaseCompare 6 | { 7 | protected readonly Processor Proc; 8 | 9 | protected BaseCompare(Processor proc) 10 | { 11 | Proc = proc; 12 | } 13 | 14 | public static ComparisonResult CompareValues(int expected, int actual, string op) 15 | { 16 | var res = new ComparisonResult 17 | { 18 | ComparisonPassed = op switch 19 | { 20 | "==" => (expected == actual), 21 | "eq" => (expected == actual), 22 | "!=" => (expected != actual), 23 | "<>" => (expected != actual), 24 | "ne" => (expected != actual), 25 | ">" => (expected > actual), 26 | ">=" => (expected >= actual), 27 | "<" => (expected < actual), 28 | "<=" => (expected <= actual), 29 | "lt" => (expected < actual), 30 | "gt" => (expected > actual), 31 | _ => false 32 | } 33 | }; 34 | 35 | 36 | if (!res.ComparisonPassed) 37 | res.FailureMessage = $"Expected {expected.ToString()} {op} {actual.ToString()}"; 38 | 39 | return res; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /sim6502/Expressions/ComparisonResult.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Barry Walker. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | namespace sim6502.Expressions 26 | { 27 | public class ComparisonResult 28 | { 29 | public string FailureMessage { get; set; } 30 | public bool ComparisonPassed { get; set; } = true; 31 | } 32 | } -------------------------------------------------------------------------------- /sim6502/Expressions/MemoryCompare.cs: -------------------------------------------------------------------------------- 1 | using sim6502.Proc; 2 | 3 | namespace sim6502.Expressions 4 | { 5 | public class MemoryCompare : BaseCompare 6 | { 7 | public MemoryCompare(Processor proc) : base(proc) 8 | { 9 | } 10 | 11 | public ComparisonResult MemoryCmp(int source, int target, int count) 12 | { 13 | var res = new ComparisonResult(); 14 | 15 | for (var i = 0; i < count; i++) 16 | { 17 | var sourceValue = Proc.ReadMemoryValueWithoutCycle(source + i); 18 | var targetValue = Proc.ReadMemoryValueWithoutCycle(target + i); 19 | 20 | if (sourceValue == targetValue) continue; 21 | 22 | res.FailureMessage = $"Expected values at memory locations {(source + i).ToString()} and " + 23 | $"{(target + i).ToString()} to match, but {(source + i).ToString()} contains " + 24 | $"{sourceValue.ToString()} and {(target + i).ToString()} contains {targetValue.ToString()}"; 25 | res.ComparisonPassed = false; 26 | break; 27 | } 28 | 29 | return res; 30 | } 31 | 32 | public ComparisonResult MemoryChk(int source, int count, int value) 33 | { 34 | var res = new ComparisonResult(); 35 | 36 | for (var i = source; i < source + count; i++) 37 | { 38 | var actualValue = Proc.ReadMemoryValueWithoutCycle(i); 39 | if (actualValue == value) continue; 40 | 41 | res.FailureMessage = $"Expected value at memory location {i.ToString()} to be {value.ToString()}, " + 42 | $"but the actual value was {actualValue.ToString()}"; 43 | res.ComparisonPassed = false; 44 | break; 45 | } 46 | 47 | return res; 48 | } 49 | 50 | public ComparisonResult MemoryVal(int location, int value, string op = "==") 51 | { 52 | var actual = value > 255 ? Proc.ReadMemoryWordWithoutCycle(location) : 53 | Proc.ReadMemoryValueWithoutCycle(location); 54 | 55 | var res = CompareValues(value, actual, op); 56 | 57 | if (!res.ComparisonPassed) 58 | { 59 | res.FailureMessage = $"Expected the value in memory location {location.ToString()} to be {op} " + 60 | $"{value.ToString()}, but the actual value was {actual.ToString()}"; 61 | } 62 | 63 | return res; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /sim6502/Grammar/Generated/sim6502.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | '.' 4 | null 5 | null 6 | null 7 | null 8 | null 9 | null 10 | null 11 | '=' 12 | '==' 13 | '>' 14 | '<' 15 | '>=' 16 | '<=' 17 | null 18 | '+' 19 | '-' 20 | '*' 21 | '/' 22 | '&' 23 | '|' 24 | '^' 25 | '$' 26 | '%' 27 | ',' 28 | '(' 29 | ')' 30 | '{' 31 | '}' 32 | '[' 33 | ']' 34 | '"' 35 | null 36 | null 37 | null 38 | null 39 | null 40 | null 41 | null 42 | null 43 | 'true' 44 | 'false' 45 | 'suites' 46 | 'suite' 47 | 'test' 48 | 'load' 49 | 'symbols' 50 | 'assert' 51 | 'jsr' 52 | 'peekbyte' 53 | 'peekword' 54 | 'memcmp' 55 | 'memchk' 56 | 'cycles' 57 | 'address' 58 | 'strip_header' 59 | 'stop_on_address' 60 | 'stop_on_rts' 61 | 'fail_on_brk' 62 | null 63 | null 64 | null 65 | null 66 | null 67 | null 68 | null 69 | null 70 | null 71 | 72 | token symbolic names: 73 | null 74 | null 75 | Boolean 76 | ProcessorFlag 77 | Register 78 | Int 79 | Hex 80 | Binary 81 | CompareOperator 82 | Assign 83 | Equal 84 | GT 85 | LT 86 | GTE 87 | LTE 88 | NotEqual 89 | Add 90 | Sub 91 | Mul 92 | Div 93 | BitAnd 94 | BitOr 95 | BitXor 96 | Dollar 97 | Percent 98 | Comma 99 | LParen 100 | RParen 101 | LBrace 102 | RBrace 103 | LBracket 104 | RBracket 105 | Quote 106 | RegA 107 | RegX 108 | RegY 109 | FlagC 110 | FlagN 111 | FlagV 112 | FlagD 113 | FlagZ 114 | BoolTrue 115 | BoolFalse 116 | Suites 117 | Suite 118 | Test 119 | Load 120 | Symbols 121 | Assert 122 | JSR 123 | PeekByte 124 | PeekWord 125 | MemoryCmp 126 | MemoryChk 127 | Cycles 128 | Address 129 | StripHeader 130 | StopOnAddress 131 | StopOnRTS 132 | FailOnBRK 133 | LoByte 134 | HiByte 135 | Byte 136 | Word 137 | Identifier 138 | StringLiteral 139 | Comment 140 | WS 141 | NewLine 142 | 143 | rule names: 144 | suites 145 | suite 146 | suiteName 147 | assignment 148 | address 149 | number 150 | boolean 151 | assertFunction 152 | assertDescription 153 | comparison 154 | compareLHS 155 | jsrFunction 156 | stopOn 157 | failOnBreak 158 | symbolsFunction 159 | symbolsFilename 160 | loadFunction 161 | loadFilename 162 | loadAddress 163 | stripHeader 164 | testFunction 165 | testName 166 | testDescription 167 | testContents 168 | peekByteFunction 169 | peekWordFunction 170 | memoryCmpFunction 171 | memoryChkFunction 172 | sourceAddress 173 | targetAddress 174 | memorySize 175 | memoryValue 176 | expression 177 | lbhb 178 | byteWord 179 | intFunction 180 | boolFunction 181 | symbolRef 182 | symbol 183 | 184 | 185 | atn: 186 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 70, 358, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 3, 2, 3, 2, 3, 2, 7, 2, 84, 10, 2, 12, 2, 14, 2, 87, 11, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 6, 3, 99, 10, 3, 13, 3, 14, 3, 100, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 3, 5, 5, 5, 125, 10, 5, 3, 6, 3, 6, 5, 6, 129, 10, 6, 3, 7, 3, 7, 3, 7, 5, 7, 134, 10, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 153, 10, 11, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 3, 12, 5, 12, 161, 10, 12, 5, 12, 163, 10, 12, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 13, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 3, 14, 5, 14, 180, 10, 14, 3, 15, 3, 15, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 18, 5, 18, 198, 10, 18, 3, 18, 5, 18, 201, 10, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 3, 22, 6, 22, 225, 10, 22, 13, 22, 14, 22, 226, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 6, 25, 236, 10, 25, 13, 25, 14, 25, 237, 3, 25, 6, 25, 241, 10, 25, 13, 25, 14, 25, 242, 3, 25, 6, 25, 246, 10, 25, 13, 25, 14, 25, 247, 5, 25, 250, 10, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 5, 34, 291, 10, 34, 3, 34, 3, 34, 5, 34, 295, 10, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 5, 34, 304, 10, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 3, 34, 7, 34, 327, 10, 34, 12, 34, 14, 34, 330, 11, 34, 3, 35, 3, 35, 5, 35, 334, 10, 35, 3, 36, 3, 36, 5, 36, 338, 10, 36, 3, 37, 3, 37, 5, 37, 342, 10, 37, 3, 38, 3, 38, 5, 38, 346, 10, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 5, 40, 356, 10, 40, 3, 40, 2, 3, 66, 41, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 2, 2, 2, 364, 2, 80, 3, 2, 2, 2, 4, 90, 3, 2, 2, 2, 6, 104, 3, 2, 2, 2, 8, 124, 3, 2, 2, 2, 10, 128, 3, 2, 2, 2, 12, 133, 3, 2, 2, 2, 14, 135, 3, 2, 2, 2, 16, 137, 3, 2, 2, 2, 18, 144, 3, 2, 2, 2, 20, 152, 3, 2, 2, 2, 22, 162, 3, 2, 2, 2, 24, 164, 3, 2, 2, 2, 26, 179, 3, 2, 2, 2, 28, 181, 3, 2, 2, 2, 30, 186, 3, 2, 2, 2, 32, 191, 3, 2, 2, 2, 34, 193, 3, 2, 2, 2, 36, 204, 3, 2, 2, 2, 38, 206, 3, 2, 2, 2, 40, 211, 3, 2, 2, 2, 42, 216, 3, 2, 2, 2, 44, 230, 3, 2, 2, 2, 46, 232, 3, 2, 2, 2, 48, 249, 3, 2, 2, 2, 50, 251, 3, 2, 2, 2, 52, 256, 3, 2, 2, 2, 54, 261, 3, 2, 2, 2, 56, 270, 3, 2, 2, 2, 58, 279, 3, 2, 2, 2, 60, 281, 3, 2, 2, 2, 62, 283, 3, 2, 2, 2, 64, 285, 3, 2, 2, 2, 66, 303, 3, 2, 2, 2, 68, 333, 3, 2, 2, 2, 70, 337, 3, 2, 2, 2, 72, 341, 3, 2, 2, 2, 74, 345, 3, 2, 2, 2, 76, 347, 3, 2, 2, 2, 78, 355, 3, 2, 2, 2, 80, 81, 7, 45, 2, 2, 81, 85, 7, 30, 2, 2, 82, 84, 5, 4, 3, 2, 83, 82, 3, 2, 2, 2, 84, 87, 3, 2, 2, 2, 85, 83, 3, 2, 2, 2, 85, 86, 3, 2, 2, 2, 86, 88, 3, 2, 2, 2, 87, 85, 3, 2, 2, 2, 88, 89, 7, 31, 2, 2, 89, 3, 3, 2, 2, 2, 90, 91, 7, 46, 2, 2, 91, 92, 7, 28, 2, 2, 92, 93, 5, 6, 4, 2, 93, 94, 7, 29, 2, 2, 94, 98, 7, 30, 2, 2, 95, 99, 5, 42, 22, 2, 96, 99, 5, 30, 16, 2, 97, 99, 5, 34, 18, 2, 98, 95, 3, 2, 2, 2, 98, 96, 3, 2, 2, 2, 98, 97, 3, 2, 2, 2, 99, 100, 3, 2, 2, 2, 100, 98, 3, 2, 2, 2, 100, 101, 3, 2, 2, 2, 101, 102, 3, 2, 2, 2, 102, 103, 7, 31, 2, 2, 103, 5, 3, 2, 2, 2, 104, 105, 7, 67, 2, 2, 105, 7, 3, 2, 2, 2, 106, 107, 5, 66, 34, 2, 107, 108, 7, 11, 2, 2, 108, 109, 5, 66, 34, 2, 109, 125, 3, 2, 2, 2, 110, 111, 5, 76, 39, 2, 111, 112, 7, 11, 2, 2, 112, 113, 5, 66, 34, 2, 113, 125, 3, 2, 2, 2, 114, 115, 5, 10, 6, 2, 115, 116, 7, 11, 2, 2, 116, 117, 5, 66, 34, 2, 117, 125, 3, 2, 2, 2, 118, 119, 7, 6, 2, 2, 119, 120, 7, 11, 2, 2, 120, 125, 5, 66, 34, 2, 121, 122, 7, 5, 2, 2, 122, 123, 7, 11, 2, 2, 123, 125, 5, 66, 34, 2, 124, 106, 3, 2, 2, 2, 124, 110, 3, 2, 2, 2, 124, 114, 3, 2, 2, 2, 124, 118, 3, 2, 2, 2, 124, 121, 3, 2, 2, 2, 125, 9, 3, 2, 2, 2, 126, 129, 5, 12, 7, 2, 127, 129, 5, 76, 39, 2, 128, 126, 3, 2, 2, 2, 128, 127, 3, 2, 2, 2, 129, 11, 3, 2, 2, 2, 130, 134, 7, 8, 2, 2, 131, 134, 7, 7, 2, 2, 132, 134, 7, 9, 2, 2, 133, 130, 3, 2, 2, 2, 133, 131, 3, 2, 2, 2, 133, 132, 3, 2, 2, 2, 134, 13, 3, 2, 2, 2, 135, 136, 7, 4, 2, 2, 136, 15, 3, 2, 2, 2, 137, 138, 7, 50, 2, 2, 138, 139, 7, 28, 2, 2, 139, 140, 5, 20, 11, 2, 140, 141, 7, 27, 2, 2, 141, 142, 5, 18, 10, 2, 142, 143, 7, 29, 2, 2, 143, 17, 3, 2, 2, 2, 144, 145, 7, 67, 2, 2, 145, 19, 3, 2, 2, 2, 146, 147, 5, 22, 12, 2, 147, 148, 7, 10, 2, 2, 148, 149, 5, 66, 34, 2, 149, 153, 3, 2, 2, 2, 150, 153, 5, 56, 29, 2, 151, 153, 5, 54, 28, 2, 152, 146, 3, 2, 2, 2, 152, 150, 3, 2, 2, 2, 152, 151, 3, 2, 2, 2, 153, 21, 3, 2, 2, 2, 154, 163, 7, 6, 2, 2, 155, 163, 7, 5, 2, 2, 156, 163, 5, 10, 6, 2, 157, 163, 7, 56, 2, 2, 158, 160, 5, 66, 34, 2, 159, 161, 5, 70, 36, 2, 160, 159, 3, 2, 2, 2, 160, 161, 3, 2, 2, 2, 161, 163, 3, 2, 2, 2, 162, 154, 3, 2, 2, 2, 162, 155, 3, 2, 2, 2, 162, 156, 3, 2, 2, 2, 162, 157, 3, 2, 2, 2, 162, 158, 3, 2, 2, 2, 163, 23, 3, 2, 2, 2, 164, 165, 7, 51, 2, 2, 165, 166, 7, 28, 2, 2, 166, 167, 5, 10, 6, 2, 167, 168, 5, 26, 14, 2, 168, 169, 5, 28, 15, 2, 169, 170, 7, 29, 2, 2, 170, 25, 3, 2, 2, 2, 171, 172, 7, 27, 2, 2, 172, 173, 7, 59, 2, 2, 173, 174, 7, 11, 2, 2, 174, 180, 5, 10, 6, 2, 175, 176, 7, 27, 2, 2, 176, 177, 7, 60, 2, 2, 177, 178, 7, 11, 2, 2, 178, 180, 5, 14, 8, 2, 179, 171, 3, 2, 2, 2, 179, 175, 3, 2, 2, 2, 180, 27, 3, 2, 2, 2, 181, 182, 7, 27, 2, 2, 182, 183, 7, 61, 2, 2, 183, 184, 7, 11, 2, 2, 184, 185, 5, 14, 8, 2, 185, 29, 3, 2, 2, 2, 186, 187, 7, 49, 2, 2, 187, 188, 7, 28, 2, 2, 188, 189, 5, 32, 17, 2, 189, 190, 7, 29, 2, 2, 190, 31, 3, 2, 2, 2, 191, 192, 7, 67, 2, 2, 192, 33, 3, 2, 2, 2, 193, 194, 7, 48, 2, 2, 194, 195, 7, 28, 2, 2, 195, 197, 5, 36, 19, 2, 196, 198, 5, 38, 20, 2, 197, 196, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 200, 3, 2, 2, 2, 199, 201, 5, 40, 21, 2, 200, 199, 3, 2, 2, 2, 200, 201, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 203, 7, 29, 2, 2, 203, 35, 3, 2, 2, 2, 204, 205, 7, 67, 2, 2, 205, 37, 3, 2, 2, 2, 206, 207, 7, 27, 2, 2, 207, 208, 7, 57, 2, 2, 208, 209, 7, 11, 2, 2, 209, 210, 5, 10, 6, 2, 210, 39, 3, 2, 2, 2, 211, 212, 7, 27, 2, 2, 212, 213, 7, 58, 2, 2, 213, 214, 7, 11, 2, 2, 214, 215, 5, 14, 8, 2, 215, 41, 3, 2, 2, 2, 216, 217, 7, 47, 2, 2, 217, 218, 7, 28, 2, 2, 218, 219, 5, 44, 23, 2, 219, 220, 7, 27, 2, 2, 220, 221, 5, 46, 24, 2, 221, 222, 7, 29, 2, 2, 222, 224, 7, 30, 2, 2, 223, 225, 5, 48, 25, 2, 224, 223, 3, 2, 2, 2, 225, 226, 3, 2, 2, 2, 226, 224, 3, 2, 2, 2, 226, 227, 3, 2, 2, 2, 227, 228, 3, 2, 2, 2, 228, 229, 7, 31, 2, 2, 229, 43, 3, 2, 2, 2, 230, 231, 7, 67, 2, 2, 231, 45, 3, 2, 2, 2, 232, 233, 7, 67, 2, 2, 233, 47, 3, 2, 2, 2, 234, 236, 5, 16, 9, 2, 235, 234, 3, 2, 2, 2, 236, 237, 3, 2, 2, 2, 237, 235, 3, 2, 2, 2, 237, 238, 3, 2, 2, 2, 238, 250, 3, 2, 2, 2, 239, 241, 5, 8, 5, 2, 240, 239, 3, 2, 2, 2, 241, 242, 3, 2, 2, 2, 242, 240, 3, 2, 2, 2, 242, 243, 3, 2, 2, 2, 243, 250, 3, 2, 2, 2, 244, 246, 5, 24, 13, 2, 245, 244, 3, 2, 2, 2, 246, 247, 3, 2, 2, 2, 247, 245, 3, 2, 2, 2, 247, 248, 3, 2, 2, 2, 248, 250, 3, 2, 2, 2, 249, 235, 3, 2, 2, 2, 249, 240, 3, 2, 2, 2, 249, 245, 3, 2, 2, 2, 250, 49, 3, 2, 2, 2, 251, 252, 7, 52, 2, 2, 252, 253, 7, 28, 2, 2, 253, 254, 5, 66, 34, 2, 254, 255, 7, 29, 2, 2, 255, 51, 3, 2, 2, 2, 256, 257, 7, 53, 2, 2, 257, 258, 7, 28, 2, 2, 258, 259, 5, 66, 34, 2, 259, 260, 7, 29, 2, 2, 260, 53, 3, 2, 2, 2, 261, 262, 7, 54, 2, 2, 262, 263, 7, 28, 2, 2, 263, 264, 5, 58, 30, 2, 264, 265, 7, 27, 2, 2, 265, 266, 5, 60, 31, 2, 266, 267, 7, 27, 2, 2, 267, 268, 5, 62, 32, 2, 268, 269, 7, 29, 2, 2, 269, 55, 3, 2, 2, 2, 270, 271, 7, 55, 2, 2, 271, 272, 7, 28, 2, 2, 272, 273, 5, 58, 30, 2, 273, 274, 7, 27, 2, 2, 274, 275, 5, 62, 32, 2, 275, 276, 7, 27, 2, 2, 276, 277, 5, 64, 33, 2, 277, 278, 7, 29, 2, 2, 278, 57, 3, 2, 2, 2, 279, 280, 5, 66, 34, 2, 280, 59, 3, 2, 2, 2, 281, 282, 5, 66, 34, 2, 282, 61, 3, 2, 2, 2, 283, 284, 5, 66, 34, 2, 284, 63, 3, 2, 2, 2, 285, 286, 5, 66, 34, 2, 286, 65, 3, 2, 2, 2, 287, 288, 8, 34, 1, 2, 288, 290, 5, 10, 6, 2, 289, 291, 5, 68, 35, 2, 290, 289, 3, 2, 2, 2, 290, 291, 3, 2, 2, 2, 291, 304, 3, 2, 2, 2, 292, 294, 5, 12, 7, 2, 293, 295, 5, 68, 35, 2, 294, 293, 3, 2, 2, 2, 294, 295, 3, 2, 2, 2, 295, 304, 3, 2, 2, 2, 296, 304, 5, 14, 8, 2, 297, 304, 5, 72, 37, 2, 298, 304, 5, 74, 38, 2, 299, 300, 7, 28, 2, 2, 300, 301, 5, 66, 34, 2, 301, 302, 7, 29, 2, 2, 302, 304, 3, 2, 2, 2, 303, 287, 3, 2, 2, 2, 303, 292, 3, 2, 2, 2, 303, 296, 3, 2, 2, 2, 303, 297, 3, 2, 2, 2, 303, 298, 3, 2, 2, 2, 303, 299, 3, 2, 2, 2, 304, 328, 3, 2, 2, 2, 305, 306, 12, 9, 2, 2, 306, 307, 7, 22, 2, 2, 307, 327, 5, 66, 34, 10, 308, 309, 12, 8, 2, 2, 309, 310, 7, 23, 2, 2, 310, 327, 5, 66, 34, 9, 311, 312, 12, 7, 2, 2, 312, 313, 7, 24, 2, 2, 313, 327, 5, 66, 34, 8, 314, 315, 12, 6, 2, 2, 315, 316, 7, 20, 2, 2, 316, 327, 5, 66, 34, 7, 317, 318, 12, 5, 2, 2, 318, 319, 7, 21, 2, 2, 319, 327, 5, 66, 34, 6, 320, 321, 12, 4, 2, 2, 321, 322, 7, 18, 2, 2, 322, 327, 5, 66, 34, 5, 323, 324, 12, 3, 2, 2, 324, 325, 7, 19, 2, 2, 325, 327, 5, 66, 34, 4, 326, 305, 3, 2, 2, 2, 326, 308, 3, 2, 2, 2, 326, 311, 3, 2, 2, 2, 326, 314, 3, 2, 2, 2, 326, 317, 3, 2, 2, 2, 326, 320, 3, 2, 2, 2, 326, 323, 3, 2, 2, 2, 327, 330, 3, 2, 2, 2, 328, 326, 3, 2, 2, 2, 328, 329, 3, 2, 2, 2, 329, 67, 3, 2, 2, 2, 330, 328, 3, 2, 2, 2, 331, 334, 7, 62, 2, 2, 332, 334, 7, 63, 2, 2, 333, 331, 3, 2, 2, 2, 333, 332, 3, 2, 2, 2, 334, 69, 3, 2, 2, 2, 335, 338, 7, 64, 2, 2, 336, 338, 7, 65, 2, 2, 337, 335, 3, 2, 2, 2, 337, 336, 3, 2, 2, 2, 338, 71, 3, 2, 2, 2, 339, 342, 5, 50, 26, 2, 340, 342, 5, 52, 27, 2, 341, 339, 3, 2, 2, 2, 341, 340, 3, 2, 2, 2, 342, 73, 3, 2, 2, 2, 343, 346, 5, 56, 29, 2, 344, 346, 5, 54, 28, 2, 345, 343, 3, 2, 2, 2, 345, 344, 3, 2, 2, 2, 346, 75, 3, 2, 2, 2, 347, 348, 7, 32, 2, 2, 348, 349, 5, 78, 40, 2, 349, 350, 7, 33, 2, 2, 350, 77, 3, 2, 2, 2, 351, 356, 7, 66, 2, 2, 352, 353, 7, 66, 2, 2, 353, 354, 7, 3, 2, 2, 354, 356, 7, 66, 2, 2, 355, 351, 3, 2, 2, 2, 355, 352, 3, 2, 2, 2, 356, 79, 3, 2, 2, 2, 29, 85, 98, 100, 124, 128, 133, 152, 160, 162, 179, 197, 200, 226, 237, 242, 247, 249, 290, 294, 303, 326, 328, 333, 337, 341, 345, 355] -------------------------------------------------------------------------------- /sim6502/Grammar/Generated/sim6502.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | Boolean=2 3 | ProcessorFlag=3 4 | Register=4 5 | Int=5 6 | Hex=6 7 | Binary=7 8 | CompareOperator=8 9 | Assign=9 10 | Equal=10 11 | GT=11 12 | LT=12 13 | GTE=13 14 | LTE=14 15 | NotEqual=15 16 | Add=16 17 | Sub=17 18 | Mul=18 19 | Div=19 20 | BitAnd=20 21 | BitOr=21 22 | BitXor=22 23 | Dollar=23 24 | Percent=24 25 | Comma=25 26 | LParen=26 27 | RParen=27 28 | LBrace=28 29 | RBrace=29 30 | LBracket=30 31 | RBracket=31 32 | Quote=32 33 | RegA=33 34 | RegX=34 35 | RegY=35 36 | FlagC=36 37 | FlagN=37 38 | FlagV=38 39 | FlagD=39 40 | FlagZ=40 41 | BoolTrue=41 42 | BoolFalse=42 43 | Suites=43 44 | Suite=44 45 | Test=45 46 | Load=46 47 | Symbols=47 48 | Assert=48 49 | JSR=49 50 | PeekByte=50 51 | PeekWord=51 52 | MemoryCmp=52 53 | MemoryChk=53 54 | Cycles=54 55 | Address=55 56 | StripHeader=56 57 | StopOnAddress=57 58 | StopOnRTS=58 59 | FailOnBRK=59 60 | LoByte=60 61 | HiByte=61 62 | Byte=62 63 | Word=63 64 | Identifier=64 65 | StringLiteral=65 66 | Comment=66 67 | WS=67 68 | NewLine=68 69 | '.'=1 70 | '='=9 71 | '=='=10 72 | '>'=11 73 | '<'=12 74 | '>='=13 75 | '<='=14 76 | '+'=16 77 | '-'=17 78 | '*'=18 79 | '/'=19 80 | '&'=20 81 | '|'=21 82 | '^'=22 83 | '$'=23 84 | '%'=24 85 | ','=25 86 | '('=26 87 | ')'=27 88 | '{'=28 89 | '}'=29 90 | '['=30 91 | ']'=31 92 | '"'=32 93 | 'true'=41 94 | 'false'=42 95 | 'suites'=43 96 | 'suite'=44 97 | 'test'=45 98 | 'load'=46 99 | 'symbols'=47 100 | 'assert'=48 101 | 'jsr'=49 102 | 'peekbyte'=50 103 | 'peekword'=51 104 | 'memcmp'=52 105 | 'memchk'=53 106 | 'cycles'=54 107 | 'address'=55 108 | 'strip_header'=56 109 | 'stop_on_address'=57 110 | 'stop_on_rts'=58 111 | 'fail_on_brk'=59 112 | -------------------------------------------------------------------------------- /sim6502/Grammar/Generated/sim6502Lexer.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | '.' 4 | null 5 | null 6 | null 7 | null 8 | null 9 | null 10 | null 11 | '=' 12 | '==' 13 | '>' 14 | '<' 15 | '>=' 16 | '<=' 17 | null 18 | '+' 19 | '-' 20 | '*' 21 | '/' 22 | '&' 23 | '|' 24 | '^' 25 | '$' 26 | '%' 27 | ',' 28 | '(' 29 | ')' 30 | '{' 31 | '}' 32 | '[' 33 | ']' 34 | '"' 35 | null 36 | null 37 | null 38 | null 39 | null 40 | null 41 | null 42 | null 43 | 'true' 44 | 'false' 45 | 'suites' 46 | 'suite' 47 | 'test' 48 | 'load' 49 | 'symbols' 50 | 'assert' 51 | 'jsr' 52 | 'peekbyte' 53 | 'peekword' 54 | 'memcmp' 55 | 'memchk' 56 | 'cycles' 57 | 'address' 58 | 'strip_header' 59 | 'stop_on_address' 60 | 'stop_on_rts' 61 | 'fail_on_brk' 62 | null 63 | null 64 | null 65 | null 66 | null 67 | null 68 | null 69 | null 70 | null 71 | 72 | token symbolic names: 73 | null 74 | null 75 | Boolean 76 | ProcessorFlag 77 | Register 78 | Int 79 | Hex 80 | Binary 81 | CompareOperator 82 | Assign 83 | Equal 84 | GT 85 | LT 86 | GTE 87 | LTE 88 | NotEqual 89 | Add 90 | Sub 91 | Mul 92 | Div 93 | BitAnd 94 | BitOr 95 | BitXor 96 | Dollar 97 | Percent 98 | Comma 99 | LParen 100 | RParen 101 | LBrace 102 | RBrace 103 | LBracket 104 | RBracket 105 | Quote 106 | RegA 107 | RegX 108 | RegY 109 | FlagC 110 | FlagN 111 | FlagV 112 | FlagD 113 | FlagZ 114 | BoolTrue 115 | BoolFalse 116 | Suites 117 | Suite 118 | Test 119 | Load 120 | Symbols 121 | Assert 122 | JSR 123 | PeekByte 124 | PeekWord 125 | MemoryCmp 126 | MemoryChk 127 | Cycles 128 | Address 129 | StripHeader 130 | StopOnAddress 131 | StopOnRTS 132 | FailOnBRK 133 | LoByte 134 | HiByte 135 | Byte 136 | Word 137 | Identifier 138 | StringLiteral 139 | Comment 140 | WS 141 | NewLine 142 | 143 | rule names: 144 | T__0 145 | Boolean 146 | ProcessorFlag 147 | Register 148 | Int 149 | Hex 150 | HexDigit 151 | Binary 152 | CompareOperator 153 | Assign 154 | Equal 155 | GT 156 | LT 157 | GTE 158 | LTE 159 | NotEqual 160 | Add 161 | Sub 162 | Mul 163 | Div 164 | BitAnd 165 | BitOr 166 | BitXor 167 | Dollar 168 | Percent 169 | Comma 170 | LParen 171 | RParen 172 | LBrace 173 | RBrace 174 | LBracket 175 | RBracket 176 | Quote 177 | RegA 178 | RegX 179 | RegY 180 | FlagC 181 | FlagN 182 | FlagV 183 | FlagD 184 | FlagZ 185 | BoolTrue 186 | BoolFalse 187 | Suites 188 | Suite 189 | Test 190 | Load 191 | Symbols 192 | Assert 193 | JSR 194 | PeekByte 195 | PeekWord 196 | MemoryCmp 197 | MemoryChk 198 | Cycles 199 | Address 200 | StripHeader 201 | StopOnAddress 202 | StopOnRTS 203 | FailOnBRK 204 | LoByte 205 | HiByte 206 | Byte 207 | Word 208 | Identifier 209 | StringLiteral 210 | String 211 | Comment 212 | WS 213 | NewLine 214 | 215 | channel names: 216 | DEFAULT_TOKEN_CHANNEL 217 | HIDDEN 218 | 219 | mode names: 220 | DEFAULT_MODE 221 | 222 | atn: 223 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 70, 485, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 3, 2, 3, 2, 3, 3, 3, 3, 5, 3, 148, 10, 3, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 5, 4, 155, 10, 4, 3, 5, 3, 5, 3, 5, 5, 5, 160, 10, 5, 3, 6, 6, 6, 163, 10, 6, 13, 6, 14, 6, 164, 3, 7, 3, 7, 6, 7, 169, 10, 7, 13, 7, 14, 7, 170, 3, 7, 3, 7, 3, 7, 6, 7, 176, 10, 7, 13, 7, 14, 7, 177, 5, 7, 180, 10, 7, 3, 8, 3, 8, 3, 9, 3, 9, 6, 9, 186, 10, 9, 13, 9, 14, 9, 187, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 5, 10, 196, 10, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 17, 3, 17, 3, 17, 3, 17, 5, 17, 217, 10, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 56, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 57, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 58, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 59, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 60, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 61, 3, 62, 3, 62, 3, 62, 3, 62, 5, 62, 426, 10, 62, 3, 63, 3, 63, 3, 63, 3, 63, 5, 63, 432, 10, 63, 3, 64, 3, 64, 3, 64, 3, 64, 5, 64, 438, 10, 64, 3, 65, 3, 65, 3, 65, 3, 65, 5, 65, 444, 10, 65, 3, 66, 6, 66, 447, 10, 66, 13, 66, 14, 66, 448, 3, 67, 3, 67, 3, 67, 3, 67, 3, 67, 3, 68, 6, 68, 457, 10, 68, 13, 68, 14, 68, 458, 3, 69, 3, 69, 7, 69, 463, 10, 69, 12, 69, 14, 69, 466, 11, 69, 3, 69, 3, 69, 3, 70, 6, 70, 471, 10, 70, 13, 70, 14, 70, 472, 3, 70, 3, 70, 3, 71, 3, 71, 5, 71, 479, 10, 71, 3, 71, 5, 71, 482, 10, 71, 3, 71, 3, 71, 2, 2, 72, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 2, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95, 48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56, 113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64, 129, 65, 131, 66, 133, 67, 135, 2, 137, 68, 139, 69, 141, 70, 3, 2, 16, 3, 2, 50, 59, 4, 2, 90, 90, 122, 122, 5, 2, 50, 59, 67, 72, 99, 104, 4, 2, 67, 67, 99, 99, 4, 2, 91, 91, 123, 123, 4, 2, 69, 69, 101, 101, 4, 2, 80, 80, 112, 112, 4, 2, 88, 88, 120, 120, 4, 2, 70, 70, 102, 102, 4, 2, 92, 92, 124, 124, 7, 2, 48, 48, 50, 59, 67, 92, 97, 97, 99, 124, 5, 2, 12, 12, 15, 15, 36, 36, 4, 2, 12, 12, 15, 15, 5, 2, 11, 12, 14, 15, 34, 34, 2, 510, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 95, 3, 2, 2, 2, 2, 97, 3, 2, 2, 2, 2, 99, 3, 2, 2, 2, 2, 101, 3, 2, 2, 2, 2, 103, 3, 2, 2, 2, 2, 105, 3, 2, 2, 2, 2, 107, 3, 2, 2, 2, 2, 109, 3, 2, 2, 2, 2, 111, 3, 2, 2, 2, 2, 113, 3, 2, 2, 2, 2, 115, 3, 2, 2, 2, 2, 117, 3, 2, 2, 2, 2, 119, 3, 2, 2, 2, 2, 121, 3, 2, 2, 2, 2, 123, 3, 2, 2, 2, 2, 125, 3, 2, 2, 2, 2, 127, 3, 2, 2, 2, 2, 129, 3, 2, 2, 2, 2, 131, 3, 2, 2, 2, 2, 133, 3, 2, 2, 2, 2, 137, 3, 2, 2, 2, 2, 139, 3, 2, 2, 2, 2, 141, 3, 2, 2, 2, 3, 143, 3, 2, 2, 2, 5, 147, 3, 2, 2, 2, 7, 154, 3, 2, 2, 2, 9, 159, 3, 2, 2, 2, 11, 162, 3, 2, 2, 2, 13, 179, 3, 2, 2, 2, 15, 181, 3, 2, 2, 2, 17, 183, 3, 2, 2, 2, 19, 195, 3, 2, 2, 2, 21, 197, 3, 2, 2, 2, 23, 199, 3, 2, 2, 2, 25, 202, 3, 2, 2, 2, 27, 204, 3, 2, 2, 2, 29, 206, 3, 2, 2, 2, 31, 209, 3, 2, 2, 2, 33, 216, 3, 2, 2, 2, 35, 218, 3, 2, 2, 2, 37, 220, 3, 2, 2, 2, 39, 222, 3, 2, 2, 2, 41, 224, 3, 2, 2, 2, 43, 226, 3, 2, 2, 2, 45, 228, 3, 2, 2, 2, 47, 230, 3, 2, 2, 2, 49, 232, 3, 2, 2, 2, 51, 234, 3, 2, 2, 2, 53, 236, 3, 2, 2, 2, 55, 238, 3, 2, 2, 2, 57, 240, 3, 2, 2, 2, 59, 242, 3, 2, 2, 2, 61, 244, 3, 2, 2, 2, 63, 246, 3, 2, 2, 2, 65, 248, 3, 2, 2, 2, 67, 250, 3, 2, 2, 2, 69, 252, 3, 2, 2, 2, 71, 254, 3, 2, 2, 2, 73, 256, 3, 2, 2, 2, 75, 258, 3, 2, 2, 2, 77, 260, 3, 2, 2, 2, 79, 262, 3, 2, 2, 2, 81, 264, 3, 2, 2, 2, 83, 266, 3, 2, 2, 2, 85, 268, 3, 2, 2, 2, 87, 273, 3, 2, 2, 2, 89, 279, 3, 2, 2, 2, 91, 286, 3, 2, 2, 2, 93, 292, 3, 2, 2, 2, 95, 297, 3, 2, 2, 2, 97, 302, 3, 2, 2, 2, 99, 310, 3, 2, 2, 2, 101, 317, 3, 2, 2, 2, 103, 321, 3, 2, 2, 2, 105, 330, 3, 2, 2, 2, 107, 339, 3, 2, 2, 2, 109, 346, 3, 2, 2, 2, 111, 353, 3, 2, 2, 2, 113, 360, 3, 2, 2, 2, 115, 368, 3, 2, 2, 2, 117, 381, 3, 2, 2, 2, 119, 397, 3, 2, 2, 2, 121, 409, 3, 2, 2, 2, 123, 425, 3, 2, 2, 2, 125, 431, 3, 2, 2, 2, 127, 437, 3, 2, 2, 2, 129, 443, 3, 2, 2, 2, 131, 446, 3, 2, 2, 2, 133, 450, 3, 2, 2, 2, 135, 456, 3, 2, 2, 2, 137, 460, 3, 2, 2, 2, 139, 470, 3, 2, 2, 2, 141, 481, 3, 2, 2, 2, 143, 144, 7, 48, 2, 2, 144, 4, 3, 2, 2, 2, 145, 148, 5, 85, 43, 2, 146, 148, 5, 87, 44, 2, 147, 145, 3, 2, 2, 2, 147, 146, 3, 2, 2, 2, 148, 6, 3, 2, 2, 2, 149, 155, 5, 75, 38, 2, 150, 155, 5, 77, 39, 2, 151, 155, 5, 83, 42, 2, 152, 155, 5, 81, 41, 2, 153, 155, 5, 79, 40, 2, 154, 149, 3, 2, 2, 2, 154, 150, 3, 2, 2, 2, 154, 151, 3, 2, 2, 2, 154, 152, 3, 2, 2, 2, 154, 153, 3, 2, 2, 2, 155, 8, 3, 2, 2, 2, 156, 160, 5, 69, 35, 2, 157, 160, 5, 71, 36, 2, 158, 160, 5, 73, 37, 2, 159, 156, 3, 2, 2, 2, 159, 157, 3, 2, 2, 2, 159, 158, 3, 2, 2, 2, 160, 10, 3, 2, 2, 2, 161, 163, 9, 2, 2, 2, 162, 161, 3, 2, 2, 2, 163, 164, 3, 2, 2, 2, 164, 162, 3, 2, 2, 2, 164, 165, 3, 2, 2, 2, 165, 12, 3, 2, 2, 2, 166, 168, 5, 49, 25, 2, 167, 169, 5, 15, 8, 2, 168, 167, 3, 2, 2, 2, 169, 170, 3, 2, 2, 2, 170, 168, 3, 2, 2, 2, 170, 171, 3, 2, 2, 2, 171, 180, 3, 2, 2, 2, 172, 173, 7, 50, 2, 2, 173, 175, 9, 3, 2, 2, 174, 176, 5, 15, 8, 2, 175, 174, 3, 2, 2, 2, 176, 177, 3, 2, 2, 2, 177, 175, 3, 2, 2, 2, 177, 178, 3, 2, 2, 2, 178, 180, 3, 2, 2, 2, 179, 166, 3, 2, 2, 2, 179, 172, 3, 2, 2, 2, 180, 14, 3, 2, 2, 2, 181, 182, 9, 4, 2, 2, 182, 16, 3, 2, 2, 2, 183, 185, 5, 51, 26, 2, 184, 186, 4, 50, 51, 2, 185, 184, 3, 2, 2, 2, 186, 187, 3, 2, 2, 2, 187, 185, 3, 2, 2, 2, 187, 188, 3, 2, 2, 2, 188, 18, 3, 2, 2, 2, 189, 196, 5, 23, 12, 2, 190, 196, 5, 25, 13, 2, 191, 196, 5, 27, 14, 2, 192, 196, 5, 29, 15, 2, 193, 196, 5, 31, 16, 2, 194, 196, 5, 33, 17, 2, 195, 189, 3, 2, 2, 2, 195, 190, 3, 2, 2, 2, 195, 191, 3, 2, 2, 2, 195, 192, 3, 2, 2, 2, 195, 193, 3, 2, 2, 2, 195, 194, 3, 2, 2, 2, 196, 20, 3, 2, 2, 2, 197, 198, 7, 63, 2, 2, 198, 22, 3, 2, 2, 2, 199, 200, 7, 63, 2, 2, 200, 201, 7, 63, 2, 2, 201, 24, 3, 2, 2, 2, 202, 203, 7, 64, 2, 2, 203, 26, 3, 2, 2, 2, 204, 205, 7, 62, 2, 2, 205, 28, 3, 2, 2, 2, 206, 207, 7, 64, 2, 2, 207, 208, 7, 63, 2, 2, 208, 30, 3, 2, 2, 2, 209, 210, 7, 62, 2, 2, 210, 211, 7, 63, 2, 2, 211, 32, 3, 2, 2, 2, 212, 213, 7, 62, 2, 2, 213, 217, 7, 64, 2, 2, 214, 215, 7, 35, 2, 2, 215, 217, 7, 63, 2, 2, 216, 212, 3, 2, 2, 2, 216, 214, 3, 2, 2, 2, 217, 34, 3, 2, 2, 2, 218, 219, 7, 45, 2, 2, 219, 36, 3, 2, 2, 2, 220, 221, 7, 47, 2, 2, 221, 38, 3, 2, 2, 2, 222, 223, 7, 44, 2, 2, 223, 40, 3, 2, 2, 2, 224, 225, 7, 49, 2, 2, 225, 42, 3, 2, 2, 2, 226, 227, 7, 40, 2, 2, 227, 44, 3, 2, 2, 2, 228, 229, 7, 126, 2, 2, 229, 46, 3, 2, 2, 2, 230, 231, 7, 96, 2, 2, 231, 48, 3, 2, 2, 2, 232, 233, 7, 38, 2, 2, 233, 50, 3, 2, 2, 2, 234, 235, 7, 39, 2, 2, 235, 52, 3, 2, 2, 2, 236, 237, 7, 46, 2, 2, 237, 54, 3, 2, 2, 2, 238, 239, 7, 42, 2, 2, 239, 56, 3, 2, 2, 2, 240, 241, 7, 43, 2, 2, 241, 58, 3, 2, 2, 2, 242, 243, 7, 125, 2, 2, 243, 60, 3, 2, 2, 2, 244, 245, 7, 127, 2, 2, 245, 62, 3, 2, 2, 2, 246, 247, 7, 93, 2, 2, 247, 64, 3, 2, 2, 2, 248, 249, 7, 95, 2, 2, 249, 66, 3, 2, 2, 2, 250, 251, 7, 36, 2, 2, 251, 68, 3, 2, 2, 2, 252, 253, 9, 5, 2, 2, 253, 70, 3, 2, 2, 2, 254, 255, 9, 3, 2, 2, 255, 72, 3, 2, 2, 2, 256, 257, 9, 6, 2, 2, 257, 74, 3, 2, 2, 2, 258, 259, 9, 7, 2, 2, 259, 76, 3, 2, 2, 2, 260, 261, 9, 8, 2, 2, 261, 78, 3, 2, 2, 2, 262, 263, 9, 9, 2, 2, 263, 80, 3, 2, 2, 2, 264, 265, 9, 10, 2, 2, 265, 82, 3, 2, 2, 2, 266, 267, 9, 11, 2, 2, 267, 84, 3, 2, 2, 2, 268, 269, 7, 118, 2, 2, 269, 270, 7, 116, 2, 2, 270, 271, 7, 119, 2, 2, 271, 272, 7, 103, 2, 2, 272, 86, 3, 2, 2, 2, 273, 274, 7, 104, 2, 2, 274, 275, 7, 99, 2, 2, 275, 276, 7, 110, 2, 2, 276, 277, 7, 117, 2, 2, 277, 278, 7, 103, 2, 2, 278, 88, 3, 2, 2, 2, 279, 280, 7, 117, 2, 2, 280, 281, 7, 119, 2, 2, 281, 282, 7, 107, 2, 2, 282, 283, 7, 118, 2, 2, 283, 284, 7, 103, 2, 2, 284, 285, 7, 117, 2, 2, 285, 90, 3, 2, 2, 2, 286, 287, 7, 117, 2, 2, 287, 288, 7, 119, 2, 2, 288, 289, 7, 107, 2, 2, 289, 290, 7, 118, 2, 2, 290, 291, 7, 103, 2, 2, 291, 92, 3, 2, 2, 2, 292, 293, 7, 118, 2, 2, 293, 294, 7, 103, 2, 2, 294, 295, 7, 117, 2, 2, 295, 296, 7, 118, 2, 2, 296, 94, 3, 2, 2, 2, 297, 298, 7, 110, 2, 2, 298, 299, 7, 113, 2, 2, 299, 300, 7, 99, 2, 2, 300, 301, 7, 102, 2, 2, 301, 96, 3, 2, 2, 2, 302, 303, 7, 117, 2, 2, 303, 304, 7, 123, 2, 2, 304, 305, 7, 111, 2, 2, 305, 306, 7, 100, 2, 2, 306, 307, 7, 113, 2, 2, 307, 308, 7, 110, 2, 2, 308, 309, 7, 117, 2, 2, 309, 98, 3, 2, 2, 2, 310, 311, 7, 99, 2, 2, 311, 312, 7, 117, 2, 2, 312, 313, 7, 117, 2, 2, 313, 314, 7, 103, 2, 2, 314, 315, 7, 116, 2, 2, 315, 316, 7, 118, 2, 2, 316, 100, 3, 2, 2, 2, 317, 318, 7, 108, 2, 2, 318, 319, 7, 117, 2, 2, 319, 320, 7, 116, 2, 2, 320, 102, 3, 2, 2, 2, 321, 322, 7, 114, 2, 2, 322, 323, 7, 103, 2, 2, 323, 324, 7, 103, 2, 2, 324, 325, 7, 109, 2, 2, 325, 326, 7, 100, 2, 2, 326, 327, 7, 123, 2, 2, 327, 328, 7, 118, 2, 2, 328, 329, 7, 103, 2, 2, 329, 104, 3, 2, 2, 2, 330, 331, 7, 114, 2, 2, 331, 332, 7, 103, 2, 2, 332, 333, 7, 103, 2, 2, 333, 334, 7, 109, 2, 2, 334, 335, 7, 121, 2, 2, 335, 336, 7, 113, 2, 2, 336, 337, 7, 116, 2, 2, 337, 338, 7, 102, 2, 2, 338, 106, 3, 2, 2, 2, 339, 340, 7, 111, 2, 2, 340, 341, 7, 103, 2, 2, 341, 342, 7, 111, 2, 2, 342, 343, 7, 101, 2, 2, 343, 344, 7, 111, 2, 2, 344, 345, 7, 114, 2, 2, 345, 108, 3, 2, 2, 2, 346, 347, 7, 111, 2, 2, 347, 348, 7, 103, 2, 2, 348, 349, 7, 111, 2, 2, 349, 350, 7, 101, 2, 2, 350, 351, 7, 106, 2, 2, 351, 352, 7, 109, 2, 2, 352, 110, 3, 2, 2, 2, 353, 354, 7, 101, 2, 2, 354, 355, 7, 123, 2, 2, 355, 356, 7, 101, 2, 2, 356, 357, 7, 110, 2, 2, 357, 358, 7, 103, 2, 2, 358, 359, 7, 117, 2, 2, 359, 112, 3, 2, 2, 2, 360, 361, 7, 99, 2, 2, 361, 362, 7, 102, 2, 2, 362, 363, 7, 102, 2, 2, 363, 364, 7, 116, 2, 2, 364, 365, 7, 103, 2, 2, 365, 366, 7, 117, 2, 2, 366, 367, 7, 117, 2, 2, 367, 114, 3, 2, 2, 2, 368, 369, 7, 117, 2, 2, 369, 370, 7, 118, 2, 2, 370, 371, 7, 116, 2, 2, 371, 372, 7, 107, 2, 2, 372, 373, 7, 114, 2, 2, 373, 374, 7, 97, 2, 2, 374, 375, 7, 106, 2, 2, 375, 376, 7, 103, 2, 2, 376, 377, 7, 99, 2, 2, 377, 378, 7, 102, 2, 2, 378, 379, 7, 103, 2, 2, 379, 380, 7, 116, 2, 2, 380, 116, 3, 2, 2, 2, 381, 382, 7, 117, 2, 2, 382, 383, 7, 118, 2, 2, 383, 384, 7, 113, 2, 2, 384, 385, 7, 114, 2, 2, 385, 386, 7, 97, 2, 2, 386, 387, 7, 113, 2, 2, 387, 388, 7, 112, 2, 2, 388, 389, 7, 97, 2, 2, 389, 390, 7, 99, 2, 2, 390, 391, 7, 102, 2, 2, 391, 392, 7, 102, 2, 2, 392, 393, 7, 116, 2, 2, 393, 394, 7, 103, 2, 2, 394, 395, 7, 117, 2, 2, 395, 396, 7, 117, 2, 2, 396, 118, 3, 2, 2, 2, 397, 398, 7, 117, 2, 2, 398, 399, 7, 118, 2, 2, 399, 400, 7, 113, 2, 2, 400, 401, 7, 114, 2, 2, 401, 402, 7, 97, 2, 2, 402, 403, 7, 113, 2, 2, 403, 404, 7, 112, 2, 2, 404, 405, 7, 97, 2, 2, 405, 406, 7, 116, 2, 2, 406, 407, 7, 118, 2, 2, 407, 408, 7, 117, 2, 2, 408, 120, 3, 2, 2, 2, 409, 410, 7, 104, 2, 2, 410, 411, 7, 99, 2, 2, 411, 412, 7, 107, 2, 2, 412, 413, 7, 110, 2, 2, 413, 414, 7, 97, 2, 2, 414, 415, 7, 113, 2, 2, 415, 416, 7, 112, 2, 2, 416, 417, 7, 97, 2, 2, 417, 418, 7, 100, 2, 2, 418, 419, 7, 116, 2, 2, 419, 420, 7, 109, 2, 2, 420, 122, 3, 2, 2, 2, 421, 422, 7, 48, 2, 2, 422, 426, 7, 110, 2, 2, 423, 424, 7, 48, 2, 2, 424, 426, 7, 78, 2, 2, 425, 421, 3, 2, 2, 2, 425, 423, 3, 2, 2, 2, 426, 124, 3, 2, 2, 2, 427, 428, 7, 48, 2, 2, 428, 432, 7, 106, 2, 2, 429, 430, 7, 48, 2, 2, 430, 432, 7, 74, 2, 2, 431, 427, 3, 2, 2, 2, 431, 429, 3, 2, 2, 2, 432, 126, 3, 2, 2, 2, 433, 434, 7, 48, 2, 2, 434, 438, 7, 100, 2, 2, 435, 436, 7, 48, 2, 2, 436, 438, 7, 68, 2, 2, 437, 433, 3, 2, 2, 2, 437, 435, 3, 2, 2, 2, 438, 128, 3, 2, 2, 2, 439, 440, 7, 48, 2, 2, 440, 444, 7, 121, 2, 2, 441, 442, 7, 48, 2, 2, 442, 444, 7, 89, 2, 2, 443, 439, 3, 2, 2, 2, 443, 441, 3, 2, 2, 2, 444, 130, 3, 2, 2, 2, 445, 447, 9, 12, 2, 2, 446, 445, 3, 2, 2, 2, 447, 448, 3, 2, 2, 2, 448, 446, 3, 2, 2, 2, 448, 449, 3, 2, 2, 2, 449, 132, 3, 2, 2, 2, 450, 451, 5, 67, 34, 2, 451, 452, 5, 135, 68, 2, 452, 453, 5, 67, 34, 2, 453, 454, 8, 67, 2, 2, 454, 134, 3, 2, 2, 2, 455, 457, 10, 13, 2, 2, 456, 455, 3, 2, 2, 2, 457, 458, 3, 2, 2, 2, 458, 456, 3, 2, 2, 2, 458, 459, 3, 2, 2, 2, 459, 136, 3, 2, 2, 2, 460, 464, 7, 61, 2, 2, 461, 463, 10, 14, 2, 2, 462, 461, 3, 2, 2, 2, 463, 466, 3, 2, 2, 2, 464, 462, 3, 2, 2, 2, 464, 465, 3, 2, 2, 2, 465, 467, 3, 2, 2, 2, 466, 464, 3, 2, 2, 2, 467, 468, 8, 69, 3, 2, 468, 138, 3, 2, 2, 2, 469, 471, 9, 15, 2, 2, 470, 469, 3, 2, 2, 2, 471, 472, 3, 2, 2, 2, 472, 470, 3, 2, 2, 2, 472, 473, 3, 2, 2, 2, 473, 474, 3, 2, 2, 2, 474, 475, 8, 70, 3, 2, 475, 140, 3, 2, 2, 2, 476, 478, 7, 15, 2, 2, 477, 479, 7, 12, 2, 2, 478, 477, 3, 2, 2, 2, 478, 479, 3, 2, 2, 2, 479, 482, 3, 2, 2, 2, 480, 482, 7, 12, 2, 2, 481, 476, 3, 2, 2, 2, 481, 480, 3, 2, 2, 2, 482, 483, 3, 2, 2, 2, 483, 484, 8, 71, 3, 2, 484, 142, 3, 2, 2, 2, 23, 2, 147, 154, 159, 164, 170, 177, 179, 187, 195, 216, 425, 431, 437, 443, 448, 458, 464, 472, 478, 481, 4, 3, 67, 2, 8, 2, 2] -------------------------------------------------------------------------------- /sim6502/Grammar/Generated/sim6502Lexer.tokens: -------------------------------------------------------------------------------- 1 | T__0=1 2 | Boolean=2 3 | ProcessorFlag=3 4 | Register=4 5 | Int=5 6 | Hex=6 7 | Binary=7 8 | CompareOperator=8 9 | Assign=9 10 | Equal=10 11 | GT=11 12 | LT=12 13 | GTE=13 14 | LTE=14 15 | NotEqual=15 16 | Add=16 17 | Sub=17 18 | Mul=18 19 | Div=19 20 | BitAnd=20 21 | BitOr=21 22 | BitXor=22 23 | Dollar=23 24 | Percent=24 25 | Comma=25 26 | LParen=26 27 | RParen=27 28 | LBrace=28 29 | RBrace=29 30 | LBracket=30 31 | RBracket=31 32 | Quote=32 33 | RegA=33 34 | RegX=34 35 | RegY=35 36 | FlagC=36 37 | FlagN=37 38 | FlagV=38 39 | FlagD=39 40 | FlagZ=40 41 | BoolTrue=41 42 | BoolFalse=42 43 | Suites=43 44 | Suite=44 45 | Test=45 46 | Load=46 47 | Symbols=47 48 | Assert=48 49 | JSR=49 50 | PeekByte=50 51 | PeekWord=51 52 | MemoryCmp=52 53 | MemoryChk=53 54 | Cycles=54 55 | Address=55 56 | StripHeader=56 57 | StopOnAddress=57 58 | StopOnRTS=58 59 | FailOnBRK=59 60 | LoByte=60 61 | HiByte=61 62 | Byte=62 63 | Word=63 64 | Identifier=64 65 | StringLiteral=65 66 | Comment=66 67 | WS=67 68 | NewLine=68 69 | '.'=1 70 | '='=9 71 | '=='=10 72 | '>'=11 73 | '<'=12 74 | '>='=13 75 | '<='=14 76 | '+'=16 77 | '-'=17 78 | '*'=18 79 | '/'=19 80 | '&'=20 81 | '|'=21 82 | '^'=22 83 | '$'=23 84 | '%'=24 85 | ','=25 86 | '('=26 87 | ')'=27 88 | '{'=28 89 | '}'=29 90 | '['=30 91 | ']'=31 92 | '"'=32 93 | 'true'=41 94 | 'false'=42 95 | 'suites'=43 96 | 'suite'=44 97 | 'test'=45 98 | 'load'=46 99 | 'symbols'=47 100 | 'assert'=48 101 | 'jsr'=49 102 | 'peekbyte'=50 103 | 'peekword'=51 104 | 'memcmp'=52 105 | 'memchk'=53 106 | 'cycles'=54 107 | 'address'=55 108 | 'strip_header'=56 109 | 'stop_on_address'=57 110 | 'stop_on_rts'=58 111 | 'fail_on_brk'=59 112 | -------------------------------------------------------------------------------- /sim6502/Grammar/SimBaseListener.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using Antlr4.Runtime.Tree; 5 | using NLog; 6 | using sim6502.Expressions; 7 | using sim6502.Grammar.Generated; 8 | using sim6502.Proc; 9 | using sim6502.Utilities; 10 | 11 | namespace sim6502.Grammar 12 | { 13 | public class SimBaseListener : sim6502BaseListener 14 | { 15 | private readonly ParseTreeProperty _intValues = new ParseTreeProperty(); 16 | private readonly ParseTreeProperty _boolValues = new ParseTreeProperty(); 17 | 18 | private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); 19 | 20 | // Whether the current test has passed 21 | private bool TestPassed => _testFailureMessages.Count == 0; 22 | 23 | // Keep track of our failure messages. We display them for any test that had failing assertions. 24 | private readonly List _testFailureMessages = new List(); 25 | 26 | // Each suite has a list of resources that we need for test, which includes the program under test 27 | // as well as any additional things like ROMS (KERNAL/BASIC - sold separately) 28 | private readonly List _suiteResources = new List(); 29 | 30 | private bool _currentSuitePassed = true; 31 | private bool _allSuitesPassed = true; 32 | private string _currentAssertion; 33 | 34 | public int TotalTestsFailed { get; private set; } 35 | public int TotalTestsPassed { get; private set; } 36 | 37 | public int TotalSuitesPassed { get; set; } = 0; 38 | 39 | public int TotalSuitesFailed { get; set; } = 0; 40 | 41 | // Make sure we do a JSR during test 42 | private bool _didJsr; 43 | 44 | public Processor Proc { get; set; } 45 | public SymbolFile Symbols { get; set; } 46 | 47 | private string CurrentSuite { get; set; } 48 | 49 | private void ResetTest() 50 | { 51 | _testFailureMessages.Clear(); 52 | _didJsr = false; 53 | Proc.ResetCycleCount(); 54 | LoadResources(); 55 | } 56 | 57 | private void FailAssertion(string message) 58 | { 59 | _testFailureMessages.Add($"{message} in assertion '{_currentAssertion}'"); 60 | FailTest(); 61 | } 62 | 63 | private void FailTest() 64 | { 65 | _currentSuitePassed = false; 66 | _allSuitesPassed = false; 67 | } 68 | 69 | private void ResetSuite() 70 | { 71 | if (TotalTestsFailed > 0) 72 | TotalSuitesFailed++; 73 | else 74 | TotalSuitesPassed++; 75 | 76 | var totalTests = TotalTestsFailed + TotalTestsPassed; 77 | var logLevel = TotalTestsFailed == 0 ? LogLevel.Info : LogLevel.Fatal; 78 | Logger.Log(logLevel, $"{TotalTestsPassed.ToString()} of {totalTests.ToString()} tests ran successfully in suite '{CurrentSuite}'."); 79 | 80 | CurrentSuite = ""; 81 | _currentSuitePassed = true; 82 | _testFailureMessages.Clear(); 83 | _suiteResources.Clear(); 84 | TotalTestsFailed = 0; 85 | TotalTestsPassed = 0; 86 | } 87 | 88 | private void LoadResources() 89 | { 90 | foreach (var lr in _suiteResources) 91 | { 92 | Utility.LoadFileIntoProcessor(Proc, lr.LoadAddress, lr.Filename, lr.StripHeader); 93 | } 94 | } 95 | 96 | private void SetIntValue(IParseTree node, int value) 97 | { 98 | _intValues.Put(node, value); 99 | } 100 | 101 | private int GetIntValue(IParseTree node) 102 | { 103 | if (node != null) 104 | return _intValues.Get(node); 105 | throw new Exception($"Tried to fetch int value for null node"); 106 | } 107 | 108 | private void SetBoolValue(IParseTree node, bool value) 109 | { 110 | _boolValues.Put(node, value); 111 | } 112 | 113 | private bool GetBoolValue(IParseTree node) 114 | { 115 | return _boolValues.Get(node); 116 | } 117 | 118 | public override void EnterSuite(sim6502Parser.SuiteContext context) 119 | { 120 | Proc = new Processor(); 121 | Proc.Reset(); 122 | CurrentSuite = context.suiteName().GetText(); 123 | Logger.Info($"Running test suite '{CurrentSuite}'..."); 124 | } 125 | 126 | public override void ExitSuite(sim6502Parser.SuiteContext context) 127 | { 128 | ResetSuite(); 129 | } 130 | 131 | public override void ExitSuites(sim6502Parser.SuitesContext context) 132 | { 133 | var logLevel = TotalSuitesFailed == 0 ? LogLevel.Info : LogLevel.Fatal; 134 | var totalSuites = TotalSuitesFailed + TotalSuitesPassed; 135 | Logger.Log(logLevel, $"{TotalSuitesPassed.ToString()} of {totalSuites.ToString()} suites passed."); 136 | } 137 | 138 | public override void ExitStripHeader(sim6502Parser.StripHeaderContext context) => SetBoolValue(context, 139 | GetBoolValue(context.boolean())); 140 | 141 | public override void ExitBoolean(sim6502Parser.BooleanContext context) => SetBoolValue(context, 142 | context.Boolean().GetText() == "true"); 143 | 144 | public override void ExitHexNumber(sim6502Parser.HexNumberContext context) => SetIntValue(context, 145 | context.Hex().GetText().ParseNumber()); 146 | 147 | public override void ExitIntNumber(sim6502Parser.IntNumberContext context) => SetIntValue(context, 148 | context.Int().GetText().ParseNumber()); 149 | 150 | public override void ExitNumberAddress(sim6502Parser.NumberAddressContext context) => SetIntValue(context, 151 | context.number().GetText().ParseNumber()); 152 | 153 | public override void ExitSymbolAddress(sim6502Parser.SymbolAddressContext context) => 154 | SymbolToInt(context.symbolRef().symbol().GetText(), context, context.symbolRef().Start.Line, 155 | context.symbolRef().Start.Column); 156 | 157 | public override void ExitSymbolRef(sim6502Parser.SymbolRefContext context) => 158 | SymbolToInt(context.symbol().GetText(), context, context.symbol().Start.Line, context.symbol().Start.Column); 159 | 160 | private void SymbolToInt(string symbol, IParseTree context, int line, int col) 161 | { 162 | if (Symbols.SymbolExists(symbol)) 163 | { 164 | var address = Symbols.SymbolToAddress(symbol); 165 | Logger.Trace($"Symbol [{symbol}] resolves to {address.ToString()}"); 166 | SetIntValue(context, address); 167 | } 168 | else 169 | { 170 | FailAssertion($"Symbol [{symbol}] was not found @ line {line.ToString()}:{col.ToString()}"); 171 | } 172 | } 173 | 174 | public override void ExitBinaryNumber(sim6502Parser.BinaryNumberContext context) => SetIntValue(context, 175 | context.Binary().GetText().ParseNumber()); 176 | 177 | public override void ExitMemoryCmpFunctionValue(sim6502Parser.MemoryCmpFunctionValueContext context) => 178 | SetBoolValue(context, GetBoolValue(context.memoryCmpFunction())); 179 | 180 | public override void ExitMemoryChkFunctionValue(sim6502Parser.MemoryChkFunctionValueContext context) => 181 | SetBoolValue(context, GetBoolValue(context.memoryChkFunction())); 182 | 183 | public override void ExitMemorySize(sim6502Parser.MemorySizeContext context) => SetIntValue(context, 184 | GetIntValue(context.expression())); 185 | 186 | public override void ExitSourceAddress(sim6502Parser.SourceAddressContext context) => SetIntValue(context, 187 | GetIntValue(context.expression())); 188 | 189 | public override void ExitTargetAddress(sim6502Parser.TargetAddressContext context) => SetIntValue(context, 190 | GetIntValue(context.expression())); 191 | 192 | public override void ExitMemoryValue(sim6502Parser.MemoryValueContext context) => SetIntValue(context, 193 | GetIntValue(context.expression())); 194 | 195 | public override void ExitLoadAddress(sim6502Parser.LoadAddressContext context) => SetIntValue(context, 196 | GetIntValue(context.address())); 197 | 198 | #region Expression Values 199 | 200 | public override void ExitSubExpressionValue(sim6502Parser.SubExpressionValueContext context) => SetIntValue(context, 201 | GetIntValue(context.expression())); 202 | 203 | public override void ExitSubValue(sim6502Parser.SubValueContext context) => SetIntValue(context, 204 | GetIntValue(context.expression(0)) - GetIntValue(context.expression(1))); 205 | 206 | public override void ExitAddValue(sim6502Parser.AddValueContext context) => SetIntValue(context, 207 | GetIntValue(context.expression(0)) + GetIntValue(context.expression(1))); 208 | 209 | public override void ExitPeekByteFunctionValue(sim6502Parser.PeekByteFunctionValueContext context) => 210 | SetIntValue(context, GetIntValue(context.peekByteFunction())); 211 | 212 | public override void ExitPeekWordFunctionValue(sim6502Parser.PeekWordFunctionValueContext context) => 213 | SetIntValue(context, GetIntValue(context.peekWordFunction())); 214 | 215 | public override void ExitDivisionValue(sim6502Parser.DivisionValueContext context) 216 | { 217 | var exp1 = GetIntValue(context.expression(0)); 218 | var exp2 = GetIntValue(context.expression(1)); 219 | 220 | try 221 | { 222 | SetIntValue(context, exp1 / exp2); 223 | } 224 | catch (DivideByZeroException) 225 | { 226 | FailAssertion($"Division by zero {exp1.ToString()} / {exp2.ToString()}"); 227 | } 228 | } 229 | 230 | public override void ExitMultiplyValue(sim6502Parser.MultiplyValueContext context) => SetIntValue(context, 231 | GetIntValue(context.expression(0)) * GetIntValue(context.expression(1))); 232 | 233 | public override void ExitIntFunctionValue(sim6502Parser.IntFunctionValueContext context) => SetIntValue(context, 234 | GetIntValue(context.intFunction())); 235 | 236 | public override void ExitBitAndExpressionValue(sim6502Parser.BitAndExpressionValueContext context) => 237 | SetIntValue(context, GetIntValue(context.expression(0)) & GetIntValue(context.expression(1))); 238 | 239 | public override void ExitBitOrExpressionValue(sim6502Parser.BitOrExpressionValueContext context) => 240 | SetIntValue(context, GetIntValue(context.expression(0)) | GetIntValue(context.expression(1))); 241 | 242 | public override void ExitBitXorExpressionValue(sim6502Parser.BitXorExpressionValueContext context) => 243 | SetIntValue(context, GetIntValue(context.expression(0)) ^ GetIntValue(context.expression(1))); 244 | 245 | public override void ExitAddressValue(sim6502Parser.AddressValueContext context) 246 | { 247 | var address = GetIntValue(context.address()); 248 | var value = address; 249 | 250 | if (context.lbhb() != null) 251 | { 252 | switch (context.lbhb().GetText()) 253 | { 254 | case ".l": 255 | value = address - ((address >> 8) * 256); 256 | Logger.Trace($"Returning LO BYTE of address {address.ToString()}: {value.ToString()}"); 257 | break; 258 | case ".h": 259 | value = address >> 8; 260 | Logger.Trace($"Returning HI BYTE of address {address.ToString()}: {value.ToString()}"); 261 | break; 262 | } 263 | } 264 | 265 | SetIntValue(context, value); 266 | } 267 | 268 | public override void ExitIntValue(sim6502Parser.IntValueContext context) => SetIntValue(context, 269 | context.number().GetText().ParseNumber()); 270 | 271 | public override void ExitBoolValue(sim6502Parser.BoolValueContext context) 272 | { 273 | SetIntValue(context, GetBoolValue(context.boolean()) ? 1 : 0); 274 | SetBoolValue(context, GetBoolValue(context.boolean())); 275 | } 276 | 277 | public override void ExitBoolFunctionValue(sim6502Parser.BoolFunctionValueContext context) 278 | { 279 | SetIntValue(context, GetBoolValue(context.boolFunction()) ? 1 : 0); 280 | SetBoolValue(context, GetBoolValue(context.boolFunction())); 281 | } 282 | 283 | #endregion 284 | 285 | #region Assignments 286 | 287 | public override void ExitExpressionAssignment(sim6502Parser.ExpressionAssignmentContext context) 288 | { 289 | Proc.WriteMemoryValue(GetIntValue(context.expression(0)), 290 | GetIntValue(context.expression(1))); 291 | } 292 | 293 | public override void ExitAddressAssignment(sim6502Parser.AddressAssignmentContext context) => WriteValueToMemory( 294 | GetIntValue(context.address()), GetIntValue(context.expression())); 295 | 296 | public override void ExitSymbolAssignment(sim6502Parser.SymbolAssignmentContext context) => WriteValueToMemory( 297 | GetIntValue(context.symbolRef()), GetIntValue(context.expression())); 298 | 299 | public override void ExitRegisterAssignment(sim6502Parser.RegisterAssignmentContext context) 300 | { 301 | var register = context.Register().GetText(); 302 | var exp = GetIntValue(context.expression()); 303 | if (exp > 255) 304 | { 305 | FailAssertion($"Cannot set the {register} register to {exp.ToString()} since it's bigger than 8 bits"); 306 | } 307 | else 308 | { 309 | switch (register) 310 | { 311 | case "a": 312 | Proc.Accumulator = exp; 313 | Logger.Trace($"Setting accumulator to {exp.ToString()}"); 314 | break; 315 | case "x": 316 | Proc.XRegister = exp; 317 | Logger.Trace($"Setting x register to {exp.ToString()}"); 318 | break; 319 | case "y": 320 | Proc.YRegister = exp; 321 | Logger.Trace($"Setting y register to {exp.ToString()}"); 322 | break; 323 | } 324 | } 325 | } 326 | 327 | public override void ExitFlagAssignment(sim6502Parser.FlagAssignmentContext context) 328 | { 329 | var flag = context.ProcessorFlag().GetText(); 330 | 331 | var expr = context.expression().GetText(); 332 | 333 | if (expr != "true" && expr != "false") 334 | expr = expr == "1" ? "true" : "false"; 335 | 336 | var val = bool.Parse(expr); 337 | 338 | switch (flag) 339 | { 340 | case "c": 341 | Proc.CarryFlag = val; 342 | break; 343 | case "n": 344 | Proc.NegativeFlag = val; 345 | break; 346 | case "z": 347 | Proc.ZeroFlag = val; 348 | break; 349 | case "v": 350 | Proc.NegativeFlag = val; 351 | break; 352 | case "d": 353 | Proc.DecimalFlag = val; 354 | break; 355 | default: 356 | FailAssertion($"Invalid flag {flag} attempted to be set to {val.ToString()}."); 357 | break; 358 | } 359 | Logger.Trace($"{flag} is being set to {val.ToString()}"); 360 | } 361 | 362 | private void WriteValueToMemory(int address, int value) 363 | { 364 | Proc.WriteMemoryValue(address, value); 365 | } 366 | 367 | #endregion 368 | 369 | #region Compares 370 | 371 | public override void ExitExpressionCompare(sim6502Parser.ExpressionCompareContext context) 372 | { 373 | var address = GetIntValue(context.expression()); 374 | var value = 0; 375 | var bw = context.byteWord(); 376 | if (bw == null || bw.GetText().ToLower().Equals(".b")) 377 | { 378 | value = Proc.ReadMemoryValueWithoutCycle(address); 379 | } 380 | if (bw != null && bw.GetText().ToLower().Equals(".w")) 381 | { 382 | value = Proc.ReadMemoryWordWithoutCycle(address); 383 | } 384 | 385 | SetIntValue(context, value); 386 | } 387 | 388 | public override void ExitAddressCompare(sim6502Parser.AddressCompareContext context) 389 | { 390 | var address = GetIntValue(context.address()); 391 | var value = Proc.ReadMemoryValueWithoutCycle(address); 392 | 393 | SetIntValue(context, value); 394 | } 395 | 396 | public override void ExitRegisterCompare(sim6502Parser.RegisterCompareContext context) 397 | { 398 | var register = context.Register().GetText(); 399 | var value = register switch 400 | { 401 | "a" => Proc.Accumulator, 402 | "x" => Proc.XRegister, 403 | "y" => Proc.YRegister, 404 | _ => -1 405 | }; 406 | 407 | Logger.Trace($"Register {register} has a value of {value.ToString()}"); 408 | SetIntValue(context, value); 409 | } 410 | 411 | public override void ExitFlagCompare(sim6502Parser.FlagCompareContext context) 412 | { 413 | var flag = context.ProcessorFlag().GetText(); 414 | var value = flag switch 415 | { 416 | "c" => Proc.CarryFlag ? 1 : 0, 417 | "z" => Proc.ZeroFlag ? 1 : 0, 418 | "d" => Proc.DecimalFlag ? 1 : 0, 419 | "v" => Proc.OverflowFlag ? 1 : 0, 420 | "n" => Proc.NegativeFlag ? 1 : 0, 421 | _ => 0 422 | }; 423 | 424 | Logger.Trace($"Flag {flag} has a value of {value.ToString()}"); 425 | SetIntValue(context, value); 426 | } 427 | 428 | public override void ExitCompareExpression(sim6502Parser.CompareExpressionContext context) 429 | { 430 | var expr = GetIntValue(context.expression()); 431 | var op = context.CompareOperator().GetText(); 432 | var lhs = GetIntValue(context.compareLHS()); 433 | 434 | var res = BaseCompare.CompareValues(lhs, expr, op); 435 | Logger.Trace($"{lhs.ToString()} {op} {expr.ToString()} : {res.ComparisonPassed.ToString()}"); 436 | if(!res.ComparisonPassed) 437 | FailAssertion(res.FailureMessage); 438 | SetBoolValue(context, res.ComparisonPassed); 439 | } 440 | 441 | public override void ExitCyclesCompare(sim6502Parser.CyclesCompareContext context) => SetIntValue(context, 442 | Proc.CycleCount); 443 | 444 | #endregion 445 | 446 | #region Functions 447 | 448 | public override void ExitSymbolsFunction(sim6502Parser.SymbolsFunctionContext context) 449 | { 450 | var filename = context.symbolsFilename().StringLiteral().GetText(); 451 | Logger.Trace($"Loading symbol file {filename}"); 452 | var symbols = File.ReadAllText(filename); 453 | Symbols = new SymbolFile(symbols); 454 | Logger.Trace($"{Symbols.SymbolCount.ToString()} symbols loaded."); 455 | } 456 | 457 | public override void ExitLoadFunction(sim6502Parser.LoadFunctionContext context) 458 | { 459 | var filename = context.loadFilename().StringLiteral().GetText(); 460 | var addrCtx = context.loadAddress(); 461 | var strip = false; 462 | if (context.stripHeader() != null) 463 | strip = GetBoolValue(context.stripHeader()); 464 | 465 | var address = addrCtx == null ? Utility.GetProgramLoadAddress(filename) : GetIntValue(context.loadAddress().address()); 466 | 467 | var lr = new LoadableResource {Filename = filename, LoadAddress = address, StripHeader = strip}; 468 | 469 | _suiteResources.Add(lr); 470 | } 471 | 472 | public override void EnterTestFunction(sim6502Parser.TestFunctionContext context) 473 | { 474 | ResetTest(); 475 | } 476 | 477 | public override void ExitTestFunction(sim6502Parser.TestFunctionContext context) 478 | { 479 | var test = context.testName().GetText(); 480 | var description = context.testDescription().GetText(); 481 | 482 | if (!_didJsr) 483 | { 484 | FailAssertion("No JSR encountered. Make sure you call the jsr function in this test!"); 485 | } 486 | 487 | if (TestPassed) 488 | { 489 | Logger.Info($"'{test} - {description}' : PASSED"); 490 | TotalTestsPassed++; 491 | } 492 | else 493 | { 494 | Logger.Fatal($"'{test} - {description}' : FAILED"); 495 | TotalTestsFailed++; 496 | foreach (var msg in _testFailureMessages) 497 | { 498 | Logger.Fatal($"'{test}' - {msg}"); 499 | } 500 | } 501 | } 502 | 503 | public override void EnterAssertFunction(sim6502Parser.AssertFunctionContext context) 504 | { 505 | _currentAssertion = context.assertDescription().GetText(); 506 | } 507 | 508 | public override void ExitAssertFunction(sim6502Parser.AssertFunctionContext context) 509 | { 510 | var success = GetBoolValue(context.comparison()); 511 | if (!success) 512 | { 513 | FailTest(); 514 | } 515 | } 516 | 517 | public override void ExitMemoryChk(sim6502Parser.MemoryChkContext context) => SetBoolValue(context, GetBoolValue(context.memoryChkFunction())); 518 | 519 | public override void ExitMemoryChkFunction(sim6502Parser.MemoryChkFunctionContext context) 520 | { 521 | var source = GetIntValue(context.sourceAddress()); 522 | var size = GetIntValue(context.memorySize()); 523 | var value = GetIntValue(context.memoryValue()); 524 | 525 | var mc = new MemoryCompare(Proc); 526 | var chk = mc.MemoryChk(source, size, value); 527 | if (!chk.ComparisonPassed) 528 | { 529 | FailAssertion(chk.FailureMessage); 530 | } 531 | 532 | SetBoolValue(context, chk.ComparisonPassed); 533 | } 534 | 535 | public override void ExitMemoryCmp(sim6502Parser.MemoryCmpContext context) => SetBoolValue(context, 536 | GetBoolValue(context.memoryCmpFunction())); 537 | 538 | public override void ExitMemoryCmpFunction(sim6502Parser.MemoryCmpFunctionContext context) 539 | { 540 | var source = GetIntValue(context.sourceAddress()); 541 | var target = GetIntValue(context.targetAddress()); 542 | var size = GetIntValue(context.memorySize()); 543 | 544 | var mc = new MemoryCompare(Proc); 545 | var cmp = mc.MemoryCmp(source, target, size); 546 | if (!cmp.ComparisonPassed) 547 | { 548 | FailAssertion(cmp.FailureMessage); 549 | } 550 | 551 | SetBoolValue(context, cmp.ComparisonPassed); 552 | } 553 | 554 | public override void ExitPeekByteFunction(sim6502Parser.PeekByteFunctionContext context) => SetIntValue(context, 555 | Proc.ReadMemoryValueWithoutCycle(GetIntValue(context.expression()))); 556 | 557 | public override void ExitPeekWordFunction(sim6502Parser.PeekWordFunctionContext context) => SetIntValue(context, 558 | Proc.ReadMemoryWordWithoutCycle(GetIntValue(context.expression()))); 559 | 560 | public override void ExitJsrFunction(sim6502Parser.JsrFunctionContext context) 561 | { 562 | var address = GetIntValue(context.address()); 563 | var failOnBrkSet = context.failOnBreak().GetText() != null; 564 | var failOnBrk = true; 565 | if (failOnBrkSet) 566 | failOnBrk = GetBoolValue(context.failOnBreak()); 567 | 568 | var stopOnRts = GetBoolValue(context.stopOn()); 569 | var stopOnAddress = GetIntValue(context.stopOn()); 570 | 571 | Logger.Trace($"Stop on address = {stopOnAddress.ToString()}"); 572 | Logger.Trace($"Stop on RTS = {stopOnRts.ToString()}"); 573 | Logger.Trace($"JSR address = {address.ToString()}"); 574 | Logger.Trace($"JSR fail_on_brk = {failOnBrk.ToString()}"); 575 | 576 | var finishedCleanly = Proc.RunRoutine(address, stopOnAddress, stopOnRts, failOnBrk); 577 | if (!finishedCleanly) 578 | { 579 | FailAssertion($"JSR call to {address.ToString()} returned an error."); 580 | } 581 | 582 | _didJsr = true; 583 | } 584 | 585 | public override void ExitStopOn(sim6502Parser.StopOnContext context) 586 | { 587 | if (context.address() != null) 588 | { 589 | SetIntValue(context, GetIntValue(context.address())); 590 | } 591 | 592 | if (context.boolean() != null) 593 | { 594 | SetBoolValue(context, GetBoolValue(context.boolean())); 595 | } 596 | } 597 | 598 | public override void ExitFailOnBreak(sim6502Parser.FailOnBreakContext context) => SetBoolValue(context, 599 | GetBoolValue(context.boolean())); 600 | 601 | #endregion 602 | 603 | } 604 | } -------------------------------------------------------------------------------- /sim6502/Grammar/SimErrorListener.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | using Antlr4.Runtime; 4 | using Antlr4.Runtime.Atn; 5 | using Antlr4.Runtime.Dfa; 6 | using Antlr4.Runtime.Sharpen; 7 | using NLog; 8 | 9 | namespace sim6502.Grammar 10 | { 11 | public class SimErrorListener : BaseErrorListener 12 | { 13 | private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); 14 | public override void SyntaxError(TextWriter output, IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, 15 | string msg, RecognitionException e) 16 | { 17 | Logger.Fatal($"Line {line.ToString()}:{charPositionInLine.ToString()} {msg}"); 18 | UnderlineError(recognizer, offendingSymbol, line, charPositionInLine); 19 | } 20 | 21 | private static void UnderlineError(IRecognizer recognizer, IToken offendingToken, int line, int charPosition) 22 | { 23 | var tokens = (CommonTokenStream)recognizer.InputStream; 24 | var input = tokens.TokenSource.InputStream.ToString(); 25 | var lines = input.Split("\n"); 26 | var errorLine = lines[line - 1]; 27 | Logger.Fatal(errorLine); 28 | var output = new StringBuilder(); 29 | 30 | for (var i = 0; i < charPosition; i++) 31 | { 32 | output.Append(" "); 33 | } 34 | var start = offendingToken.StartIndex; 35 | var stop = offendingToken.StopIndex; 36 | if (start >= 0 && stop >= 0) 37 | { 38 | for (var i = start; i <= stop; i++) 39 | { 40 | output.Append("^"); 41 | } 42 | } 43 | Logger.Fatal(output.ToString()); 44 | } 45 | 46 | public override void ReportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, bool exact, BitSet ambigAlts, 47 | ATNConfigSet configs) 48 | { 49 | base.ReportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /sim6502/Grammar/sim6502.g4: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Barry Walker. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | grammar sim6502; 26 | 27 | suites 28 | : Suites LBrace (suite)* RBrace 29 | ; 30 | 31 | suite 32 | : Suite LParen suiteName RParen LBrace (testFunction | symbolsFunction | loadFunction)+ RBrace 33 | ; 34 | 35 | suiteName 36 | : StringLiteral 37 | ; 38 | 39 | assignment 40 | : expression Assign expression # expressionAssignment 41 | | symbolRef Assign expression # symbolAssignment 42 | | address Assign expression # addressAssignment 43 | | Register Assign expression # registerAssignment 44 | | ProcessorFlag Assign expression # flagAssignment 45 | ; 46 | 47 | address 48 | : number # numberAddress 49 | | symbolRef # symbolAddress 50 | ; 51 | 52 | number 53 | : Hex # hexNumber 54 | | Int # intNumber 55 | | Binary # binaryNumber 56 | ; 57 | 58 | boolean 59 | : Boolean 60 | ; 61 | 62 | assertFunction 63 | : Assert LParen comparison Comma assertDescription RParen 64 | ; 65 | 66 | assertDescription 67 | : StringLiteral 68 | ; 69 | 70 | comparison 71 | : compareLHS CompareOperator expression # compareExpression 72 | | memoryChkFunction # memoryChk 73 | | memoryCmpFunction # memoryCmp 74 | ; 75 | 76 | compareLHS 77 | : Register # registerCompare 78 | | ProcessorFlag # flagCompare 79 | | address # addressCompare 80 | | Cycles # cyclesCompare 81 | | expression (byteWord)? # expressionCompare 82 | ; 83 | 84 | jsrFunction 85 | : JSR LParen address stopOn failOnBreak RParen 86 | ; 87 | 88 | stopOn 89 | : Comma StopOnAddress Assign address 90 | | Comma StopOnRTS Assign boolean 91 | ; 92 | 93 | failOnBreak 94 | : Comma FailOnBRK Assign boolean 95 | ; 96 | 97 | symbolsFunction 98 | : Symbols LParen symbolsFilename RParen 99 | ; 100 | 101 | symbolsFilename 102 | : StringLiteral 103 | ; 104 | 105 | loadFunction 106 | : Load LParen loadFilename (loadAddress)? (stripHeader)? RParen 107 | ; 108 | 109 | loadFilename 110 | : StringLiteral 111 | ; 112 | 113 | loadAddress 114 | : Comma Address Assign address 115 | ; 116 | 117 | stripHeader 118 | : Comma StripHeader Assign boolean 119 | ; 120 | 121 | testFunction 122 | : Test LParen testName Comma testDescription RParen LBrace testContents+ RBrace 123 | ; 124 | 125 | testName 126 | : StringLiteral 127 | ; 128 | 129 | testDescription 130 | : StringLiteral 131 | ; 132 | 133 | testContents 134 | : assertFunction+ 135 | | assignment+ 136 | | jsrFunction+ 137 | ; 138 | 139 | peekByteFunction 140 | : PeekByte LParen expression RParen 141 | ; 142 | 143 | peekWordFunction 144 | : PeekWord LParen expression RParen 145 | ; 146 | 147 | memoryCmpFunction 148 | : MemoryCmp LParen sourceAddress Comma targetAddress Comma memorySize RParen 149 | ; 150 | 151 | memoryChkFunction 152 | : MemoryChk LParen sourceAddress Comma memorySize Comma memoryValue RParen 153 | ; 154 | 155 | sourceAddress 156 | : expression 157 | ; 158 | 159 | targetAddress 160 | : expression 161 | ; 162 | 163 | memorySize 164 | : expression 165 | ; 166 | 167 | memoryValue 168 | : expression 169 | ; 170 | 171 | expression 172 | : address (lbhb)? # addressValue 173 | | number (lbhb)? # intValue 174 | | boolean # boolValue 175 | | intFunction # intFunctionValue 176 | | boolFunction # boolFunctionValue 177 | | LParen expression RParen # subExpressionValue 178 | | expression BitAnd expression # bitAndExpressionValue 179 | | expression BitOr expression # bitOrExpressionValue 180 | | expression BitXor expression # bitXorExpressionValue 181 | | expression Mul expression # multiplyValue 182 | | expression Div expression # divisionValue 183 | | expression Add expression # addValue 184 | | expression Sub expression # subValue 185 | ; 186 | 187 | lbhb 188 | : LoByte # loByte 189 | | HiByte # hiByte 190 | ; 191 | 192 | byteWord 193 | : Byte # byteValue 194 | | Word # wordValue 195 | ; 196 | 197 | intFunction 198 | : peekByteFunction # peekByteFunctionValue 199 | | peekWordFunction # peekWordFunctionValue 200 | ; 201 | 202 | boolFunction 203 | : memoryChkFunction # memoryChkFunctionValue 204 | | memoryCmpFunction # memoryCmpFunctionValue 205 | ; 206 | 207 | symbolRef 208 | : LBracket symbol RBracket 209 | ; 210 | 211 | symbol 212 | : Identifier 213 | | Identifier '.' Identifier 214 | ; 215 | 216 | Boolean 217 | : BoolTrue 218 | | BoolFalse 219 | ; 220 | 221 | ProcessorFlag 222 | : FlagC 223 | | FlagN 224 | | FlagZ 225 | | FlagD 226 | | FlagV 227 | ; 228 | 229 | Register 230 | : RegA 231 | | RegX 232 | | RegY 233 | ; 234 | 235 | Int 236 | : [0-9] + 237 | ; 238 | 239 | Hex 240 | : Dollar HexDigit + 241 | | '0' [xX] HexDigit + 242 | ; 243 | 244 | fragment 245 | HexDigit 246 | : [0-9a-fA-F] 247 | ; 248 | 249 | Binary 250 | : Percent ('0' | '1') + 251 | ; 252 | 253 | CompareOperator 254 | : Equal 255 | | GT 256 | | LT 257 | | GTE 258 | | LTE 259 | | NotEqual 260 | ; 261 | 262 | Assign: '=' ; 263 | Equal: '==' ; 264 | GT: '>' ; 265 | LT: '<' ; 266 | GTE: '>=' ; 267 | LTE: '<=' ; 268 | NotEqual 269 | : '<>' 270 | | '!=' 271 | ; 272 | Add: '+' ; 273 | Sub: '-' ; 274 | Mul: '*' ; 275 | Div: '/' ; 276 | BitAnd: '&' ; 277 | BitOr: '|' ; 278 | BitXor: '^' ; 279 | Dollar: '$' ; 280 | Percent: '%' ; 281 | Comma: ',' ; 282 | 283 | LParen: '(' ; 284 | RParen: ')' ; 285 | LBrace: '{' ; 286 | RBrace: '}' ; 287 | LBracket: '[' ; 288 | RBracket: ']' ; 289 | Quote: '"' ; 290 | 291 | RegA: [aA] ; 292 | RegX: [xX] ; 293 | RegY: [yY] ; 294 | 295 | FlagC: [cC] ; 296 | FlagN: [nN] ; 297 | FlagV: [vV] ; 298 | FlagD: [dD] ; 299 | FlagZ: [zZ] ; 300 | 301 | BoolTrue: 'true' ; 302 | BoolFalse: 'false' ; 303 | 304 | Suites: 'suites' ; 305 | Suite: 'suite' ; 306 | Test: 'test' ; 307 | Load: 'load' ; 308 | Symbols: 'symbols' ; 309 | Assert: 'assert' ; 310 | JSR: 'jsr' ; 311 | PeekByte: 'peekbyte' ; 312 | PeekWord: 'peekword' ; 313 | MemoryCmp: 'memcmp'; 314 | MemoryChk: 'memchk'; 315 | Cycles: 'cycles' ; 316 | Address: 'address'; 317 | StripHeader: 'strip_header'; 318 | StopOnAddress: 'stop_on_address'; 319 | StopOnRTS: 'stop_on_rts'; 320 | FailOnBRK: 'fail_on_brk'; 321 | 322 | LoByte: '.l' | '.L' ; 323 | HiByte: '.h' | '.H' ; 324 | 325 | Byte: '.b' | '.B' ; 326 | Word: '.w' | '.W' ; 327 | 328 | Identifier 329 | : [a-zA-Z0-9_.]+ 330 | ; 331 | 332 | StringLiteral 333 | : Quote String Quote 334 | {Text = Text.Substring(1, Text.Length - 2);} 335 | ; 336 | 337 | fragment 338 | String 339 | : ~ ["\n\r]+ 340 | ; 341 | 342 | Comment 343 | : ';' ~ [\r\n]* -> skip 344 | ; 345 | 346 | WS 347 | : [ \t\r\n\u000C]+ -> skip 348 | ; 349 | 350 | NewLine 351 | : ( '\r' '\n'? 352 | | '\n' 353 | ) 354 | -> skip 355 | ; -------------------------------------------------------------------------------- /sim6502/Proc/AddressingMode.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Aaron Mell 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | namespace sim6502.Proc 27 | { 28 | /// 29 | /// The addressing modes used by the 6502 Processor 30 | /// 31 | public enum AddressingMode 32 | { 33 | /// 34 | /// In this mode a full address is given to operation on IE: Memory byte[] { 0x60, 0x00, 0xFF } 35 | /// would perform an ADC operation and Add the value at ADDRESS 0xFF00 to the accumulator. 36 | /// The address is always LSB first 37 | /// 38 | Absolute = 1, 39 | 40 | /// 41 | /// In this mode a full address is given to operation on IE: Memory byte[] { 0x7D, 0x00, 0xFF } The full value would then be added to the X Register. 42 | /// If the X register was 0x01 then the address would be 0xFF01. and the value stored there would have an ADC operation performed on it and the value would 43 | /// be added to the accumulator. 44 | /// 45 | AbsoluteX = 2, 46 | 47 | /// 48 | /// In this mode a full address is given to operation on IE: Memory byte[] { 0x79, 0x00, 0xFF } The full value would then be added to the Y Register. 49 | /// If the Y register was 0x01 then the address would be 0xFF01. and the value stored there would have an ADC operation performed on it and the value would 50 | /// be added to the accumulator 51 | /// 52 | AbsoluteY = 3, 53 | 54 | /// 55 | /// In this mode the instruction operates on the accumulator. No operands are needed. 56 | /// 57 | Accumulator = 4, 58 | 59 | /// 60 | /// In this mode, the value to operate on immediately follows the instruction. IE: Memory byte[] { 0x69, 0x01 } 61 | /// would perform an ADC operation and Add 0x01 directly to the accumulator 62 | /// 63 | Immediate = 5, 64 | 65 | /// 66 | /// No address is needed for this mode. EX: BRK (Break), CLC (Clear Carry Flag) etc 67 | /// 68 | Implied = 6, 69 | 70 | /// 71 | /// In this mode assume the following 72 | /// Memory = { 0x61, 0x02, 0x04, 0x00, 0x03 } 73 | /// RegisterX = 0x01 74 | /// 1. Take the sum of the X Register and the value after the opcode 0x01 + 0x01 = 0x02. 75 | /// 2. Starting at position 0x02 get an address (0x04,0x00) = 0x0004 76 | /// 3. Perform the ADC operation and Add the value at 0x0005 to the accumulator 77 | /// Note: if the Zero Page address is greater than 0xff then roll over the value. IE 0x101 rolls over to 0x01 78 | /// 79 | IndirectX = 7, 80 | 81 | /// 82 | /// In this mode assume the following 83 | /// Memory = { 0x61, 0x02, 0x04, 0x00, 0x03 } 84 | /// RegisterY = 0x01 85 | /// 1. Starting at position 0x02 get an address (0x04,0x00) = 0x0004 86 | /// 2. Take the sum of the Y Register and the absolute address 0x01+0x0004 = 0x0005 87 | /// 3. Perform the ADC operation and Add the value at 0x0005 to the accumulator 88 | /// Note: if the address is great that 0xffff then roll over IE: 0x10001 rolls over to 0x01 89 | /// 90 | IndirectY = 8, 91 | 92 | /// 93 | /// JMP is the only operation that uses this mode. In this mode an absolute address is specified that points to the location of the absolute address we want to jump to. 94 | /// 95 | Indirect = 9, 96 | 97 | /// 98 | /// This Mode Changes the PC. It allows the program to change the location of the PC by 127 in either direction. 99 | /// 100 | Relative = 10, 101 | 102 | /// 103 | /// In this mode, a zero page address of the value to operate on is specified. This mode can only operation on values between 0x0 and 0xFF, or those that sit on the zero page of memory. IE: Memory byte[] { 0x69, 0x02, 0x01 } 104 | /// would perform an ADC operation and Add 0x01 directly to the Accumulator 105 | /// 106 | ZeroPage = 11, 107 | 108 | /// 109 | /// In this mode, a zero page address of the value to operate on is specified, however the value of the X register is added to the address IE: Memory byte[] { 0x86, 0x02, 0x01, 0x67, 0x04, 0x01 } 110 | /// In this example we store a value of 0x01 into the X register, then we would perform an ADC operation using the address of 0x04+0x01=0x05 and Add the result of 0x01 directly to the Accumulator 111 | /// 112 | ZeroPageX = 12, 113 | 114 | /// 115 | /// This works the same as ZeroPageX except it uses the Y register instead of the X register. 116 | /// 117 | ZeroPageY = 13, 118 | } 119 | } -------------------------------------------------------------------------------- /sim6502/Proc/Disassembly.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Aaron Mell 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | using System; 27 | 28 | namespace sim6502.Proc 29 | { 30 | /// 31 | /// Used to help simulating. This class contains the disassembly properties. 32 | /// 33 | [Serializable] 34 | public class Disassembly 35 | { 36 | /// 37 | /// The low Address 38 | /// 39 | public string LowAddress { get; set; } 40 | 41 | /// 42 | /// The High Address 43 | /// 44 | public string HighAddress { get; set; } 45 | 46 | /// 47 | /// The string representation of the OpCode 48 | /// 49 | public string OpCodeString { get; set; } 50 | 51 | /// 52 | /// The disassembly of the current step 53 | /// 54 | public string DisassemblyOutput { get; set; } 55 | } 56 | } -------------------------------------------------------------------------------- /sim6502/Proc/LoadableResource.cs: -------------------------------------------------------------------------------- 1 | namespace sim6502.Proc 2 | { 3 | /// 4 | /// Used by the testing framework to keep track of the resources that we have to load 5 | /// on each test executed. The resources are specified at the suite level, but since 6 | /// the processor is reset on each test, we need to reload these resources so that our 7 | /// tests can run cleanly. 8 | /// 9 | public class LoadableResource 10 | { 11 | /// 12 | /// The filename of the resource to load 13 | /// 14 | public string Filename { get; set; } 15 | 16 | /// 17 | /// The address to load the resource at. If not specified, will use the first 2 bytes 18 | /// as the load address. If the load address is the first 2 bytes, make sure you specify 19 | /// StripHeader = true so that we don't load the header bytes into memory. 20 | /// 21 | public int LoadAddress { get; set; } 22 | 23 | /// 24 | /// Whether to strip the first 2 bytes of the file. For .prg files, you generally want to set this 25 | /// to true since the load address was specified using the first 2 bytes of the file. For ROMS like 26 | /// KERNAL and BASIC, leave this as false 27 | /// 28 | public bool StripHeader { get; set; } = false; 29 | } 30 | } -------------------------------------------------------------------------------- /sim6502/Sim6502CLI.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Barry Walker. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | using System; 26 | using System.Diagnostics; 27 | using System.IO; 28 | using System.Reflection; 29 | using Antlr4.Runtime; 30 | using Antlr4.Runtime.Tree; 31 | using CommandLine; 32 | using NLog; 33 | using sim6502.Grammar; 34 | using sim6502.Grammar.Generated; 35 | using Parser = CommandLine.Parser; 36 | 37 | // ReSharper disable UnusedAutoPropertyAccessor.Local 38 | 39 | namespace sim6502 40 | { 41 | internal class Sim6502Cli 42 | { 43 | private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); 44 | 45 | // ReSharper disable once ClassNeverInstantiated.Local 46 | private class Options 47 | { 48 | [Option('t', "trace", SetName = "trace", Required = false, Default = false, 49 | HelpText = "Enable or disable trace mode")] 50 | public bool Trace { get; set; } 51 | 52 | [Option('d', "debug", SetName = "debug", Required = false, Default = false, 53 | HelpText = "Enable or disable debug mode")] 54 | public bool Debug { get; set; } 55 | 56 | [Option('s', "suitefile", Required = true, HelpText = "The path to your suite file which contains your test suites")] 57 | public string SuiteFile { get; set; } 58 | } 59 | 60 | private static int Main(string[] args) 61 | { 62 | var assembly = Assembly.GetEntryAssembly()?.Location; 63 | var versionInfo = FileVersionInfo.GetVersionInfo(assembly); 64 | 65 | Logger.Info($"{versionInfo.ProductName} v{versionInfo.ProductVersion} {versionInfo.LegalCopyright}"); 66 | Logger.Info("https://github.com/barryw/sim6502"); 67 | 68 | return Parser.Default 69 | .ParseArguments(args) 70 | .MapResult( 71 | RunCli, 72 | errs => 1); 73 | } 74 | 75 | private static int RunCli(Options opts) 76 | { 77 | SetLogLevel(opts); 78 | 79 | try 80 | { 81 | if(!File.Exists(opts.SuiteFile)) 82 | throw new FileNotFoundException($"The suite file {opts.SuiteFile} could not be found."); 83 | 84 | return RunTests(opts); 85 | } 86 | catch (Exception ex) 87 | { 88 | Logger.Fatal(ex, $"Failed to run tests: {ex.Message}, {ex.StackTrace}"); 89 | return 1; 90 | } 91 | } 92 | 93 | private static int RunTests(Options opts) 94 | { 95 | var afs = new AntlrFileStream(opts.SuiteFile); 96 | var lexer = new sim6502Lexer(afs); 97 | var tokens = new CommonTokenStream(lexer); 98 | var parser = new sim6502Parser(tokens) {BuildParseTree = true}; 99 | var tree = parser.suites(); 100 | var walker = new ParseTreeWalker(); 101 | var sbl = new SimBaseListener(); 102 | 103 | walker.Walk(sbl, tree); 104 | 105 | return sbl.TotalSuitesFailed == 0 ? 0 : 1; 106 | } 107 | 108 | private static void SetLogLevel(Options opts) 109 | { 110 | LogManager.Configuration.Variables["cliLogLevel"] = LogLevel.Info.Name; 111 | if (opts.Debug) 112 | LogManager.Configuration.Variables["cliLogLevel"] = LogLevel.Debug.Name; 113 | if (opts.Trace) 114 | LogManager.Configuration.Variables["cliLogLevel"] = LogLevel.Trace.Name; 115 | 116 | LogManager.ReconfigExistingLoggers(); 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /sim6502/Utilities/SymbolFile.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Barry Walker. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.IO; 28 | using System.Text.RegularExpressions; 29 | 30 | namespace sim6502.Utilities 31 | { 32 | public class SymbolFile 33 | { 34 | private readonly string[] _symbolfile; 35 | 36 | private readonly string[] _lineTerminationCharacters = {"\r\n", "\r", "\n"}; 37 | private const string LabelConstant = ".label"; 38 | private const string NamespaceConstant = ".namespace"; 39 | private const string LabelRegex = @".label\s+([A-Za-z0-9_]+)=([A-Fa-f0-9$]+)"; 40 | private const string NamespaceRegex = @".namespace ([A-Za-z0-9_]+)"; 41 | 42 | private Dictionary Symbols { get; } = new Dictionary(); 43 | 44 | public int SymbolCount => Symbols.Count; 45 | 46 | public SymbolFile(string symbolfile) 47 | { 48 | _symbolfile = symbolfile.Trim().Split( 49 | _lineTerminationCharacters, 50 | StringSplitOptions.None 51 | ); 52 | ParseSymbolFile(); 53 | } 54 | 55 | public SymbolFile(Dictionary symbols) 56 | { 57 | Symbols = symbols; 58 | } 59 | 60 | private void ParseSymbolFile() 61 | { 62 | var currentNamespace = ""; 63 | 64 | foreach (var currentLine in _symbolfile) 65 | { 66 | var trimmedLine = currentLine.TrimStart(); 67 | 68 | if (trimmedLine.StartsWith(LabelConstant)) 69 | { 70 | ProcessFoundLabel(trimmedLine, currentNamespace); 71 | } 72 | else if (trimmedLine.StartsWith(NamespaceConstant)) 73 | { 74 | currentNamespace = ProcessFoundNamespace(trimmedLine); 75 | } 76 | else 77 | { 78 | currentNamespace = ""; 79 | } 80 | } 81 | } 82 | 83 | private void ProcessFoundLabel(string currentLine, string currentNamespace) 84 | { 85 | var labelMatch = Regex.Match(currentLine, LabelRegex, RegexOptions.IgnoreCase); 86 | if (!labelMatch.Success) return; 87 | 88 | var label = labelMatch.Groups[1].Value; 89 | var address = labelMatch.Groups[2].Value; 90 | 91 | Symbols.Add(currentNamespace.Empty() ? label : $"{currentNamespace}.{label}", 92 | address.ParseNumber()); 93 | } 94 | 95 | private static string ProcessFoundNamespace(string currentLine) 96 | { 97 | var namespaceMatch = Regex.Match(currentLine, NamespaceRegex, RegexOptions.IgnoreCase); 98 | return !namespaceMatch.Success ? null : namespaceMatch.Groups[1].Value; 99 | } 100 | 101 | public bool SymbolExists(string symbol) 102 | { 103 | return Symbols.ContainsKey(symbol); 104 | } 105 | 106 | public int SymbolToAddress(string symbol) 107 | { 108 | return Symbols[symbol]; 109 | } 110 | 111 | public string AddressToSymbol(int address, bool asHex = true) 112 | { 113 | var symbol = asHex ? address.ToHex() : address.ToString(); 114 | 115 | foreach (var (key, value) in Symbols) 116 | { 117 | if (value != address) continue; 118 | symbol = key; 119 | break; 120 | } 121 | 122 | return symbol; 123 | } 124 | 125 | public static SymbolFile LoadSymbolFile(string symbolFilename) 126 | { 127 | if ("".Equals(symbolFilename) || symbolFilename == null) 128 | return null; 129 | 130 | Utility.FileExists(symbolFilename); 131 | 132 | var symbolFile = File.ReadAllText(symbolFilename); 133 | return new SymbolFile(symbolFile); 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /sim6502/Utilities/Utility.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Barry Walker. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | using System; 26 | using System.Collections.Generic; 27 | using System.IO; 28 | using NLog; 29 | using sim6502.Proc; 30 | 31 | namespace sim6502.Utilities 32 | { 33 | public static class Utility 34 | { 35 | private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); 36 | 37 | public static bool Empty(this string str) 38 | { 39 | return string.IsNullOrEmpty(str); 40 | } 41 | 42 | public static string ToHex(this int number) 43 | { 44 | var numDigits = 1; 45 | if (number >= 16) 46 | numDigits++; 47 | if (number >= 256) 48 | numDigits++; 49 | if (number >= 4096) 50 | numDigits++; 51 | 52 | var hex = number.ToString($"X{numDigits}").ToLower(); 53 | return $"${hex}"; 54 | } 55 | 56 | public static int ParseNumber(this string number) 57 | { 58 | int retval; 59 | if (number.StartsWith("$")) 60 | { 61 | number = number.Replace("$", "0x"); 62 | retval = Convert.ToInt32(number, 16); 63 | } 64 | else if (number.StartsWith("0x")) 65 | { 66 | retval = Convert.ToInt32(number, 16); 67 | } 68 | else if (number.StartsWith("%")) 69 | { 70 | number = number.Replace("%", ""); 71 | retval = Convert.ToInt32(number, 2); 72 | } 73 | else 74 | { 75 | retval = int.Parse(number); 76 | } 77 | 78 | return retval; 79 | } 80 | 81 | public static int GetProgramLoadAddress(string filename) 82 | { 83 | var buffer = new byte[2]; 84 | using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) 85 | { 86 | fs.Read(buffer, 0, 2); 87 | } 88 | 89 | return GetProgramLoadAddress(buffer); 90 | } 91 | 92 | public static int GetProgramLoadAddress(byte[] program) 93 | { 94 | return program[1] * 256 + program[0]; 95 | } 96 | 97 | public static void LoadFileIntoProcessor(Processor proc, int address, string filename, bool stripHeader = false) 98 | { 99 | Logger.Trace($"Loading {filename} @ {address.ToHex()}"); 100 | FileExists(filename); 101 | using var file = new FileStream(filename, FileMode.Open, FileAccess.Read); 102 | var program = new List(StreamToBytes(file)); 103 | 104 | if (stripHeader) 105 | { 106 | Logger.Trace($"Stripping header bytes before load."); 107 | program.RemoveAt(0); 108 | program.RemoveAt(0); 109 | } 110 | 111 | proc.LoadProgram(address, program.ToArray(), address, false); 112 | } 113 | 114 | private static IEnumerable StreamToBytes(Stream stream) 115 | { 116 | using var ms = new MemoryStream(); 117 | stream.CopyTo(ms); 118 | return ms.ToArray(); 119 | } 120 | 121 | public static void FileExists(string filename) 122 | { 123 | if (File.Exists(filename)) return; 124 | Logger.Fatal($"The file '{filename}' does not exist."); 125 | throw new FileNotFoundException(); 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /sim6502/nlog.config: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /sim6502/sim6502.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.0 6 | Copyright © 2020 Barry Walker. All Rights Reserved. 7 | Barry Walker 8 | 6502 Simulator Test Runner CLI 9 | 2.0.0 10 | 2.0.0 11 | 2.0.0 12 | https://github.com/barryw/sim6502 13 | 6502 Test Runner 14 | Barry Walker 15 | Sim6502TestRunner 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ..\dependencies\NCalc.dll 28 | 29 | 30 | 31 | 32 | 33 | PreserveNewest 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-1.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 1") { 3 | ; Load the program under test 4 | load("TestPrograms/include_me_full.prg", strip_header = true) 5 | 6 | test("test-1", "Quick test of assignments") { 7 | ; Test to make sure we can resolve symbols 8 | [Loc1] = $abcd 9 | [Loc2] = $d0 10 | 11 | ; Make sure we can write to ZP and non-ZP addresses 12 | $c002 = $dcba 13 | $81 = $0d 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-10.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 9") { 3 | ; Load the program under test 4 | load("TestPrograms/include_me_full.prg", strip_header = true) 5 | 6 | test("test-1", "Make sure we can access lo/hi bytes in assert compares") { 7 | [Loc1] = $abcd 8 | 9 | assert([Loc1].w == $abcd, "Compare a memory word") 10 | ;assert([Loc1] + $01 == $abcd.h, "HI byte") 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-2.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 2") { 3 | ; Load the program under test 4 | load("TestPrograms/include_me_full.prg", strip_header = true) 5 | 6 | test("test-1", "Quick test of assignments") { 7 | ; Make sure we can assign symbol values to all 3 registers 8 | x = [Val1] 9 | a = [Val2] 10 | y = [Val3] 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-3.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 3") { 3 | ; Load the program under test 4 | load("TestPrograms/include_me_full.prg", strip_header = true) 5 | 6 | test("test-1", "Quick test of assignments") { 7 | [Loc1] = [Val1] 8 | [Loc2] = [Val2] 9 | [Loc3] = [Val3] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-4.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 4") { 3 | ; Load the program under test 4 | load("TestPrograms/include_me_full.prg", strip_header = true) 5 | 6 | test("test-1", "Quick test of assignments") { 7 | c = 1 8 | n = false 9 | z = true 10 | v = 0 11 | d = [FALSE] 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-5.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 5") { 3 | ; Load the program under test 4 | symbols("TestPrograms/include_me_full.sym") 5 | load("TestPrograms/include_me_full.prg", strip_header = true) 6 | 7 | test("test-1", "Test JSR function") { 8 | [r0L] = $bd ; Write the value $bd 9 | [r1] = $1234 ; Write to location $1234 10 | [r2] = $12c ; Write 300 bytes 11 | 12 | jsr([FillMemory], stop_on_rts = true, fail_on_brk = true) 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-6.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 6") { 3 | ; Load the program under test 4 | symbols("TestPrograms/include_me_full.sym") 5 | load("TestPrograms/include_me_full.prg", strip_header = true) 6 | 7 | test("test-1", "Assert test 1") { 8 | [r0L] = $bd ; Write the value $bd 9 | [r1] = $1234 ; Write to location $1234 10 | [r2] = $12c ; Write 300 bytes 11 | 12 | $4000 = peekbyte([r0L]) 13 | $4001 = peekword([r1]) 14 | $4003 = peekword([r2]) 15 | 16 | jsr([FillMemory], stop_on_rts = true, fail_on_brk = true) 17 | 18 | a = $00 19 | c = false 20 | 21 | assert(memchk(peekword($4001), peekword($4003), peekbyte($4000)), "Make sure memory was set correctly") 22 | assert($4000 == $bd, "Make sure $4000 contains the byte we're writing") 23 | assert(a == $00, "Make sure accumulator is zero") 24 | assert(c == false, "Make sure carry flag clear") 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-7.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 7") { 3 | ; Load the program under test 4 | symbols("TestPrograms/include_me_full.sym") 5 | load("TestPrograms/include_me_full.prg", strip_header = true) 6 | 7 | test("test-1", "Make sure all registers are settable") { 8 | a = $f0 9 | x = $f1 10 | y = $f2 11 | 12 | [dick] = $10 13 | 14 | assert(a == $f0, "Make sure accumulator is $f0") 15 | assert(x == $f1, "Make sure accumulator is $f1") 16 | assert(y == $f2, "Make sure accumulator is $f2") 17 | } 18 | 19 | test("memory-fill-1", "Fill an uneven block of memory") { 20 | [r0L] = $bd ; Stuff $bd into our memory locations. Odd number, right? 21 | [r1] = $1234 ; Start at $1234 22 | [r2] = $12c ; and do 300 bytes 23 | 24 | jsr([FillMemory], stop_on_rts = true, fail_on_brk = true) 25 | 26 | assert(cycles < 85, "We can fill this block in fewer than 85 cycles") 27 | assert(memchk($1234, $12c, $bd), "Memory was filled properly") 28 | } 29 | 30 | test("memory-copy-1", "Ensure memory copy works") { 31 | [r0] = $e000 ; Copy the KERNAL rom 32 | [r1] = $4000 ; into $4000 33 | [r2] = $2000 ; Copy all 8k of it 34 | 35 | jsr([CopyMemory], stop_on_rts = true, fail_on_brk = true) 36 | 37 | assert(cycles < 200000, "Ensure that we run in fewer than 200000 cycles") 38 | assert(memcmp($e000, $4000, $2000), "Ensure that KERNAL was copied correctly") 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-8.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 8") { 3 | ; Load the program under test 4 | load("TestPrograms/include_me_full.prg", strip_header = true) 5 | 6 | test("test-1", "Make sure we can evaluate assignment expressions") { 7 | [Loc1] = $abcd 8 | [Loc1] + $02 = $d0 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /sim6502tests/GrammarTests/test-9.txt: -------------------------------------------------------------------------------- 1 | suites { 2 | suite("Test Suite 9") { 3 | ; Load the program under test 4 | load("TestPrograms/include_me_full.prg", strip_header = true) 5 | 6 | test("test-1", "Make sure we can evaluate assignment expressions") { 7 | [Loc1] = $abcd 8 | [Loc1] + $02 = $d0 9 | 10 | assert([Loc1] + $02 == $d0, "Awww yea!") 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /sim6502tests/RegisterMode.cs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Aaron Mell 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | namespace sim6502tests 27 | { 28 | /// 29 | /// An enum helper, used when testing addressing modes for Comparison and Store operations 30 | /// 31 | public enum RegisterMode 32 | { 33 | /// 34 | /// CMP Operation 35 | /// 36 | Accumulator = 1, 37 | 38 | /// 39 | /// CPX Operation 40 | /// 41 | XRegister = 2, 42 | 43 | /// 44 | /// CPY Operation 45 | /// 46 | YRegister = 3 47 | } 48 | } -------------------------------------------------------------------------------- /sim6502tests/SymbolFileTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using sim6502; 3 | using sim6502.Utilities; 4 | 5 | namespace sim6502tests 6 | { 7 | [TestFixture] 8 | public class SymbolFileTests 9 | { 10 | [Test] 11 | public void TestAddSymbols() 12 | { 13 | var symfile = ".label MyLabel=$0801\n.label YourLabel=$c000\n .label OurLabel=49152"; 14 | var sf = new SymbolFile(symfile); 15 | 16 | Assert.AreEqual(2049, sf.SymbolToAddress("MyLabel")); 17 | Assert.AreEqual(49152, sf.SymbolToAddress("YourLabel")); 18 | Assert.AreEqual(49152, sf.SymbolToAddress("OurLabel")); 19 | } 20 | 21 | [Test] 22 | public void TestNamespaces() 23 | { 24 | var symfile = 25 | ".label NonNamespacedLabel=$400\n.namespace kernal {\n .label NamespacedLabel=$ffff\n}\n.label AnotherNonNamespacedLabel=$0800"; 26 | var sf = new SymbolFile(symfile); 27 | 28 | Assert.AreEqual(1024, sf.SymbolToAddress("NonNamespacedLabel")); 29 | Assert.AreEqual(65535, sf.SymbolToAddress("kernal.NamespacedLabel")); 30 | Assert.AreEqual(2048, sf.SymbolToAddress("AnotherNonNamespacedLabel")); 31 | } 32 | 33 | [Test] 34 | public void TestLookupByAddress() 35 | { 36 | var symfile = 37 | ".label NonNamespacedLabel=$400\n.namespace kernal {\n .label NamespacedLabel=$ffff\n}\n.label AnotherNonNamespacedLabel=$0800"; 38 | var sf = new SymbolFile(symfile); 39 | 40 | Assert.AreEqual("NonNamespacedLabel", sf.AddressToSymbol(1024)); 41 | Assert.AreEqual("kernal.NamespacedLabel", sf.AddressToSymbol(65535)); 42 | Assert.AreEqual("AnotherNonNamespacedLabel", sf.AddressToSymbol(2048)); 43 | 44 | Assert.AreEqual("$401", sf.AddressToSymbol(1025)); 45 | Assert.AreEqual("1025", sf.AddressToSymbol(1025, false)); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /sim6502tests/TestPrograms/include_me_full.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryw/sim6502/cdc88363904d14c1292ab5cdcf013fa68fe7c41d/sim6502tests/TestPrograms/include_me_full.prg -------------------------------------------------------------------------------- /sim6502tests/TestPrograms/include_me_full.sym: -------------------------------------------------------------------------------- 1 | .label r2=$61 2 | .label r3=$63 3 | .label r4=$65 4 | .label r5=$67 5 | .label r6=$69 6 | .label r7=$6b 7 | .label r4H=$66 8 | .label r0H=$fc 9 | .label r4L=$65 10 | .label TIMER_ONE_SECOND=$3c 11 | .label SPR_NORMAL=$0 12 | .label r0L=$fb 13 | .label SPR_MULTICOLOR=$80 14 | .label JOY_DOWN=$2 15 | .namespace vic { 16 | .label EXTCOL=$d020 17 | .label SP3X=$d006 18 | .label SP3Y=$d007 19 | .label SP7COL=$d02e 20 | .label SP3COL=$d02a 21 | .label SPENA=$d015 22 | .label ScreenMemoryBase=$206f 23 | .label DEFAULT_SCREEN_BASE=$400 24 | .label SPMC=$d01c 25 | .label COLOR=$286 26 | .label LPENY=$d014 27 | .label SCREEN_MEM_POINTER_MASK=$f0 28 | .label LPENX=$d013 29 | .label SCROLX=$d016 30 | .label SP2Y=$d005 31 | .label SCROLY=$d011 32 | .label CharacterMemoryBase=$2073 33 | .label SP2X=$d004 34 | .label SP6Y=$d00d 35 | .label IRQMSK=$d01a 36 | .label SP4COL=$d02b 37 | .label SP0COL=$d027 38 | .label DEFAULT_VIC_BANK=$0 39 | .label BGCOL3=$d024 40 | .label SpritePointerBase=$2071 41 | .label BankMemoryBase=$206d 42 | .label SP7X=$d00e 43 | .label SP7Y=$d00f 44 | .label DEFAULT_SPRITE_POINTER_BASE=$7f8 45 | .label VICIRQ=$d019 46 | .label BGCOL0=$d021 47 | .label DEFAULT_CHAR_BASE=$1000 48 | .label BGCOL1=$d022 49 | .label BGCOL2=$d023 50 | .label XXPAND=$d01d 51 | .label SP1X=$d002 52 | .label SP1Y=$d003 53 | .label SP5X=$d00a 54 | .label SP5Y=$d00b 55 | .label SCREEN_MEM_REV_POINTER_MASK=$f 56 | .label SP5COL=$d02c 57 | .label SPBGPR=$d01b 58 | .label SP1COL=$d028 59 | .label SPSPCL=$d01e 60 | .label RASTER=$d012 61 | .label SP6X=$d00c 62 | .label YXPAND=$d017 63 | .label SP0Y=$d001 64 | .label SP0X=$d000 65 | .label SPBGCL=$d01f 66 | .label SP4Y=$d009 67 | .label VMCSB=$d018 68 | .label SP6COL=$d02d 69 | .label SP4X=$d008 70 | .label SPMC1=$d026 71 | .label SPMC0=$d025 72 | .label SP2COL=$d029 73 | .label CHAR_MEM_POINTER_MASK=$e 74 | .label COLCLK=$d81a 75 | .label MSIGX=$d010 76 | .label CHAR_MEM_REV_POINTER_MASK=$f1 77 | } 78 | .label SPR_HIDE=$0 79 | .label c64lib_joy_left=$73 80 | .label CopyMemory=$21b8 81 | .label TIMER_FOUR_SECONDS=$f0 82 | .label SPR_VISIBLE=$15 83 | .namespace kernal { 84 | .label VEC_SAVE=$ffd8 85 | .label VEC_STOP=$ffe1 86 | .label ILOAD=$330 87 | .label RND=$e097 88 | .label CLOSE=$e1c7 89 | .label VEC_SETTMO=$ffa2 90 | .label VEC_SECOND=$ff93 91 | .label RADDC=$e092 92 | .label IRQVEC=$314 93 | .label VEC_SETMSG=$ff90 94 | .label VEC_TKSA=$ff96 95 | .label IBASIN=$324 96 | .label VEC_CIOUT=$ffa8 97 | .label VEC_UDTIM=$ffea 98 | .label VEC_IOBASE=$fff3 99 | .label IGETIN=$32a 100 | .label ICLALL=$32c 101 | .label VEC_LISTEN=$ffb1 102 | .label VEC_PLOT=$fff0 103 | .label SYS=$e12a 104 | .label VEC_CLOSE=$ffc3 105 | .label VEC_CLRCHN=$ffcc 106 | .label VEC_MEMBOT=$ff99 107 | .label CINV=$314 108 | .label VEC_SETNAM=$ffbd 109 | .label VEC_CLALL=$ffe7 110 | .label VEC_SETTIM=$ffdb 111 | .label VEC_LOAD=$ffd5 112 | .label VEC_CHRIN=$ffcf 113 | .label IOPEN=$31a 114 | .label VEC_UNLSN=$ffae 115 | .label VEC_RESTOR=$ff8a 116 | .label VEC_CHROUT=$ffd2 117 | .label FREE1=$334 118 | .label LOAD=$e168 119 | .label VEC_GETIN=$ffe4 120 | .label FREE2=$3fc 121 | .label VEC_VECTOR=$ff8d 122 | .label ICLOSE=$31c 123 | .label VERIFY=$e165 124 | .label IBSOUT=$326 125 | .label VEC_SETLFS=$ffba 126 | .label VEC_RAMTAS=$ff87 127 | .label VEC_UNTLK=$ffab 128 | .label IRQNOR=$ea31 129 | .label VEC_OPEN=$ffc0 130 | .label VEC_RDTIM=$ffde 131 | .label RMULC=$e08d 132 | .label VEC_MEMTOP=$ff9c 133 | .label SAVE=$e156 134 | .label CBINV=$316 135 | .label NMINV=$318 136 | .label VEC_ACPTR=$ffa5 137 | .label VEC_SCNKEY=$ff9f 138 | .label ICLRCH=$322 139 | .label ISTOP=$328 140 | .label ICHKIN=$31e 141 | .label VEC_SCREEN=$ffed 142 | .label USRCMD=$32e 143 | .label LSTX=$c5 144 | .label POLY1=$e043 145 | .label POLY2=$e059 146 | .label VEC_IOINIT=$ff84 147 | .label ISAVE=$332 148 | .label TBUFFER=$33c 149 | .label OPEN=$e1be 150 | .label CLRSCR=$e544 151 | .label VEC_CINT=$ff81 152 | .label VEC_READST=$ffb7 153 | .label ICKOUT=$320 154 | .label VEC_CHKOUT=$ffc9 155 | .label HOME=$e566 156 | .label VEC_TALK=$ffb4 157 | .label VEC_CHKIN=$ffc6 158 | } 159 | .label SPR_FG=$0 160 | .label JOY_BUTTON=$10 161 | .label SPR_BG=$80 162 | .label JOY_RIGHT=$8 163 | .label DISABLE=$0 164 | .label BANK=$0 165 | .label r5H=$68 166 | .label SPR_PRIORITY=$1b 167 | .label SPR_SHOW=$80 168 | .label BitMaskPow2=$20c3 169 | .label r1H=$fe 170 | .label r5L=$67 171 | .label TRUE=$80 172 | .label ENABLE=$80 173 | .label r1L=$fd 174 | .label BankLookup=$2069 175 | .label ReadJoystick=$2245 176 | .label SPR_HIRES=$0 177 | .namespace cia { 178 | .label CIACRA=$dc0e 179 | .label CI2PRA=$dd00 180 | .label BANK_1_MASK=$2 181 | .label CIAICR=$dc0d 182 | .label CI2PRB=$dd01 183 | .label VIC_BANK_REVERSE_MASK=$fc 184 | .label C2DDRB=$dd03 185 | .label C2DDRA=$dd02 186 | .label TO2TEN=$dd08 187 | .label CIACRB=$dc0f 188 | .label TODHRS=$dc0b 189 | .label CI2CRB=$dd0f 190 | .label CI2CRA=$dd0e 191 | .label BANK_3_MASK=$0 192 | .label VIC_BANK_MASK=$3 193 | .label TO2HRS=$dd0b 194 | .label BANK_0_MASK=$3 195 | .label CI2ICR=$dd0d 196 | .label CIASDR=$dc0c 197 | .label TODTEN=$dc08 198 | .label CI2SDR=$dd0c 199 | .label CIDDRA=$dc02 200 | .label CIDDRB=$dc03 201 | .label BANK_2_MASK=$1 202 | .label TIMBLO=$dc06 203 | .label TO2SEC=$dd09 204 | .label TIMALO=$dc04 205 | .label TO2MIN=$dd0a 206 | .label TIMBHI=$dc07 207 | .label TI2ALO=$dd04 208 | .label TIMAHI=$dc05 209 | .label TI2BHI=$dd07 210 | .label TI2AHI=$dd05 211 | .label TODSEC=$dc09 212 | .label TODMIN=$dc0a 213 | .label TI2BLO=$dd06 214 | .label CIAPRA=$dc00 215 | .label CIAPRB=$dc01 216 | } 217 | .namespace basic { 218 | .label PRINT=$aaa0 219 | .label TOK_POS=$b9 220 | .label TOK_LIST=$9b 221 | .label FDCEND=$bf3a 222 | .label GETSTK=$a3fb 223 | .label DORE1=$b016 224 | .label ERROR=$a437 225 | .label FRMEVAL=$ad9e 226 | .label TOK_STR=$c4 227 | .label CHKOPN=$aefa 228 | .label MOV2F=$bbc7 229 | .label EXIGNT=$acfc 230 | .label QPLOP=$a717 231 | .label GOSUB=$a883 232 | .label POS=$b39e 233 | .label TOK_SUB=$ab 234 | .label TOK_STEP=$a9 235 | .label TOK_TO=$a4 236 | .label DATAN=$a906 237 | .label TOK_VERIFY=$95 238 | .label FSUB=$b850 239 | .label TOK_MID=$ca 240 | .label TOK_DIV=$ad 241 | .label PRINTN=$aa80 242 | .label TOK_ATN=$c1 243 | .label FDIV=$bb0f 244 | .label TOK_REM=$8f 245 | .label TOK_SGN=$b4 246 | .label ASC=$b78b 247 | .label ABS=$bc58 248 | .label BLTU=$a3b8 249 | .label TOK_ADD=$aa 250 | .label DOAGIN=$ab4d 251 | .label PARCHK=$aef1 252 | .label TOK_CHR=$c7 253 | .label FADD=$b867 254 | .label MULSHF=$b983 255 | .label TOK_CLOSE=$a0 256 | .label ANDOP=$afe9 257 | .label FONE=$b9bc 258 | .label TOK_ABS=$b6 259 | .label TOK_ASC=$c6 260 | .label DIM=$b018 261 | .label RUN=$a871 262 | .label FRESTR=$b6a3 263 | .label STMDSP=$a00c 264 | .label STRD=$b465 265 | .label ARYGET=$b194 266 | .label ERRTAB=$a19e 267 | .label TOK_RUN=$8a 268 | .label REM=$a93b 269 | .label MULDIV=$bab7 270 | .label MOVAF=$bc0c 271 | .label SGN=$bc39 272 | .label TOK_DIM=$86 273 | .label NEGFAC=$b947 274 | .label TOK_OR=$b0 275 | .label TOK_SQR=$ba 276 | .label GETADR=$b7f7 277 | .label FHALF=$bf11 278 | .label FOUTBL=$bf1c 279 | .label FUWAIT=$b82d 280 | .label TOK_AND=$af 281 | .label FCERR=$b248 282 | .label MLTPLY=$ba59 283 | .label GETFNM=$b3e1 284 | .label TOK_MULT=$ac 285 | .label BSERR=$b245 286 | .label TOK_ON=$91 287 | .label FNDOER=$b3f4 288 | .label TOK_RETURN=$8e 289 | .label FINPTR=$b185 290 | .label TOK_CONT=$9a 291 | .label MUL10=$bae2 292 | .label FOR=$a742 293 | .label CHKCLS=$aef7 294 | .label CRUNCH=$a579 295 | .label STRLIT=$b487 296 | .label FDIVT=$bb12 297 | .label END=$a831 298 | .label EVAL=$ae83 299 | .label CONUPK=$ba8c 300 | .label LIST=$a69c 301 | .label GONE=$a7e4 302 | .label FADDT=$b86a 303 | .label TOK_LEN=$c3 304 | .label FINLOG=$bd7e 305 | .label TOK_EXP=$bd 306 | .label TOK_LET=$88 307 | .label RESLST=$a09e 308 | .label MOVFA=$bbfc 309 | .label RETURN=$a8d2 310 | .label GARBAG=$b526 311 | .label FADDH=$b849 312 | .label NEXT=$ad1e 313 | .label TOK_RESTORE=$8c 314 | .label MOVFM=$bba2 315 | .label OMERR=$a435 316 | .label TOK_LOAD=$93 317 | .label FRMNUM=$ad8a 318 | .label FADD4=$b8a7 319 | .label PIVAL=$aea8 320 | .label PTRGET=$b08b 321 | .label INPUTN=$aba5 322 | .label TOK_GOSUB=$8d 323 | .label TOK_INT=$b5 324 | .label TOK_NEXT=$82 325 | .label N32768=$b1a5 326 | .label TOK_DEF=$96 327 | .label ISARY=$b1d1 328 | .label MOVEF=$bc0f 329 | .label FRE=$b37d 330 | .label ONGOTO=$a94b 331 | .label LINGET=$a96b 332 | .label EXPCON=$bfbf 333 | .label TOK_GET=$a1 334 | .label VAL=$b7ad 335 | .label TOK_POKE=$97 336 | .label INLIN=$a560 337 | .label FOUT=$bddd 338 | .label TOK_RIGHT=$c9 339 | .label TOK_READ=$87 340 | .label SCRTCH=$a642 341 | .label LINKPRG=$a533 342 | .label STROUT=$ab1e 343 | .label CMD=$aa86 344 | .label TOK_DATA=$83 345 | .label IF=$a928 346 | .label RUNC=$a68e 347 | .label READY=$a474 348 | .label OROP=$afe6 349 | .label TOK_LT=$b3 350 | .label LOG=$b9ea 351 | .label AYINT=$b1bf 352 | .label TOK_CMD=$9d 353 | .label CONT=$a857 354 | .label TOK_LOG=$bc 355 | .label GET=$ab7b 356 | .label MIDD=$b737 357 | .label NEGOP=$bfb4 358 | .label TOK_PEEK=$c2 359 | .label TOK_TAB=$a3 360 | .label TOK_USR=$b7 361 | .label GOTO=$a8a0 362 | .label CHRD=$b6ec 363 | .label TOK_SPC=$a6 364 | .label MLDVEX=$bad4 365 | .label LEFTD=$b700 366 | .label TOK_GOTO=$89 367 | .label TOK_TAN=$c0 368 | .label TOK_NEW=$a2 369 | .label RESTOR=$a81d 370 | .label LINPRT=$bdcd 371 | .label TOK_RND=$bb 372 | .label TOK_IF=$8b 373 | .label ERRDIR=$b3a6 374 | .label NOTFNS=$b11d 375 | .label PREAM=$b761 376 | .label INPRT=$bdc0 377 | .label TOK_SAVE=$94 378 | .label FINDLN=$a613 379 | .label TOK_WAIT=$92 380 | .label INTIDX=$b1b2 381 | .label GETBYTC=$b79b 382 | .label GETNUM=$b7eb 383 | .label CBMBASIC=$a004 384 | .label TOK_INPUTN=$84 385 | .label TOK_INPUT=$85 386 | .label FNDFOR=$a38a 387 | .label CHKCOM=$aeff 388 | .label FRETMS=$b6db 389 | .label FSUBT=$b853 390 | .label PEEK=$b80d 391 | .label NORMAL=$b8fe 392 | .label TOK_COS=$be 393 | .label OVERR=$b97e 394 | .label TOK_THEN=$a7 395 | .label TOK_NOT=$a8 396 | .label INPUT=$abbf 397 | .label FMULT=$ba28 398 | .label OPTAB=$a080 399 | .label TOK_END=$80 400 | .label TOK_SIN=$bf 401 | .label GIVAYF=$b391 402 | .label TOK_GT=$b1 403 | .label GETSPA=$b4f4 404 | .label TOK_PRINTN=$98 405 | .label MAIN=$a480 406 | .label SIGN=$bc2b 407 | .label REASON=$a408 408 | .label NEWSTT=$a7ae 409 | .label LOGCN2=$b9c1 410 | .label FCOMP=$bc5b 411 | .label TOK_PRINT=$99 412 | .label READ=$ac06 413 | .label DIV10=$bafe 414 | .label TOK_OPEN=$9f 415 | .label DATA=$a8f8 416 | .label SQR=$bf71 417 | .label ISVAR=$af2b 418 | .label CAT=$b63d 419 | .label TOK_SYS=$9e 420 | .label SNERR=$af08 421 | .label MOVINS=$b67a 422 | .label POKE=$b824 423 | .label TOK_FOR=$81 424 | .label TENC=$baf9 425 | .label MAIN1=$a49c 426 | .label ROUND=$bc1b 427 | .label TOK_EQ=$b2 428 | .label TOK_FRE=$b8 429 | .label INT=$bccc 430 | .label FPWRT=$bf7b 431 | .label TOK_VAL=$c5 432 | .label UMULT=$b34c 433 | .label NO999=$bdb3 434 | .label RIGHTD=$b72c 435 | .label TOK_CLR=$9c 436 | .label ISFUN=$afa7 437 | .label TOK_FN=$a5 438 | .label DEF=$b3b3 439 | .label TOK_EXPN=$ae 440 | .label FIN=$bcf3 441 | .label LEN=$b77c 442 | .label LET=$a9a5 443 | .label QINT=$bc9b 444 | .label EXP=$bfed 445 | .label TOK_STOP=$90 446 | .label TOK_LEFT=$c8 447 | .label CLEAR=$a65e 448 | } 449 | .label TIMER_HALF_SECOND=$1e 450 | .label TIMER_THREE_SECONDS=$b4 451 | .label EnDisTimer=$2189 452 | .label UpdateTimers=$2112 453 | .label TIMER_SINGLE=$0 454 | .label SPR_X_EXPAND=$1d 455 | .label r6H=$6a 456 | .label ChangeSpriteAttribute=$20a7 457 | .label r2H=$62 458 | .label r6L=$69 459 | .label PositionSprite=$2075 460 | .label r2L=$61 461 | .namespace sid { 462 | .label ATDCY1=$d405 463 | .label ATDCY2=$d40c 464 | .label ATDCY3=$d413 465 | .label SUREL3=$d414 466 | .label SUREL1=$d406 467 | .label SUREL2=$d40d 468 | .label FREHI1=$d401 469 | .label FRELO3=$d40e 470 | .label FRELO2=$d407 471 | .label POTY=$d41a 472 | .label FRELO1=$d400 473 | .label PWHI3=$d411 474 | .label PWHI2=$d40a 475 | .label PWHI1=$d403 476 | .label POTX=$d419 477 | .label RANDOM=$d41b 478 | .label ENV3=$d41c 479 | .label SIGVOL=$d418 480 | .label FREHI3=$d40f 481 | .label FREHI2=$d408 482 | .label PWLO1=$d402 483 | .label PWLO2=$d409 484 | .label PWLO3=$d410 485 | .label VCREG3=$d412 486 | .label CUTHI=$d416 487 | .label RESON=$d417 488 | .label VCREG2=$d40b 489 | .label VCREG1=$d404 490 | .label CUTLO=$d415 491 | } 492 | .label JOY_UP=$1 493 | .label JOY_LEFT=$4 494 | .label ReadJoysticks=$223b 495 | .label TIMER_TWO_SECONDS=$78 496 | .label TIMER_CONTINUOUS=$1 497 | .label CreateTimer=$20e3 498 | .label c64lib_joy_btn=$6d 499 | .label SPR_Y_EXPAND=$17 500 | .label SetVICBank=$2000 501 | .label ClearTimers=$20cb { 502 | } 503 | .label c64lib_timers=$33c 504 | .label r7H=$6c 505 | .label r3H=$64 506 | .label r7L=$6b 507 | .label Keyboard=$228c { 508 | .label Buffer=$248d 509 | .label TooManyNewKeys=$243e 510 | .label Return=$2429 511 | .label BufferQuantity=$2491 512 | .label SimultaneousAlphanumericKeysFlag=$2492 513 | .label KeyInRow=$228f 514 | .label NoActivityDetected=$22df 515 | .label BufferEmpty=$2427 516 | .label Exist=$240a 517 | .label KeyFound=$22c7 518 | .label ControlPort=$22f1 519 | .label KeyTable=$244a 520 | .label BufferOld=$248a 521 | .label Main=$22f5 522 | .label OverFlow=$22d7 523 | } 524 | .label r3L=$63 525 | .label FillMemory=$2195 526 | .label SPR_HMC=$1c 527 | .label UpdateBaseLocations=$2037 528 | .label FALSE=$0 529 | .label VIC_START=$0 530 | .label SPR_EXPAND=$80 531 | .label TIMER_STRUCT_BYTES=$40 532 | .label c64lib_joy_right=$75 533 | .label r0=$fb 534 | .label c64lib_joy_up=$6f 535 | .label c64lib_joy_down=$71 536 | .label r1=$fd 537 | -------------------------------------------------------------------------------- /sim6502tests/TestSuiteParser.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Antlr4.Runtime; 3 | using Antlr4.Runtime.Tree; 4 | using NUnit.Framework; 5 | using sim6502.Grammar; 6 | using sim6502.Grammar.Generated; 7 | using sim6502.Utilities; 8 | 9 | namespace sim6502tests 10 | { 11 | [TestFixture] 12 | public class TestSuiteParser 13 | { 14 | private static sim6502Parser.SuitesContext GetContext(string test) 15 | { 16 | var afs = new AntlrFileStream(test); 17 | var lexer = new sim6502Lexer(afs); 18 | var tokens = new CommonTokenStream(lexer); 19 | var parser = new sim6502Parser(tokens); 20 | parser.RemoveErrorListeners(); 21 | parser.AddErrorListener(new SimErrorListener()); 22 | parser.BuildParseTree = true; 23 | return parser.suites(); 24 | } 25 | 26 | [Test] 27 | public void TestSuite1() 28 | { 29 | var symbols = new Dictionary(); 30 | 31 | symbols.Add("MySymbol", 0xa000); 32 | symbols.Add("Loc1", 0xc000); 33 | symbols.Add("Loc2", 0x80); 34 | 35 | var symbolFile = new SymbolFile(symbols); 36 | 37 | var tree = GetContext("GrammarTests/test-1.txt"); 38 | 39 | var walker = new ParseTreeWalker(); 40 | var sbl = new SimBaseListener(); 41 | 42 | sbl.Symbols = symbolFile; 43 | 44 | walker.Walk(sbl, tree); 45 | 46 | Assert.AreEqual(0xd0, sbl.Proc.ReadMemoryValueWithoutCycle(0x80)); 47 | Assert.AreEqual(0xabcd, sbl.Proc.ReadMemoryWordWithoutCycle(0xc000)); 48 | Assert.AreEqual(0xdcba, sbl.Proc.ReadMemoryWordWithoutCycle(0xc002)); 49 | Assert.AreEqual(0x0d, sbl.Proc.ReadMemoryValueWithoutCycle(0x81)); 50 | } 51 | 52 | [Test] 53 | public void TestSuite2() 54 | { 55 | var symbols = new Dictionary {{"Val1", 0x11}, {"Val2", 0x22}, {"Val3", 0xff}}; 56 | var symbolFile = new SymbolFile(symbols); 57 | 58 | var tree = GetContext("GrammarTests/test-2.txt"); 59 | 60 | var walker = new ParseTreeWalker(); 61 | var sbl = new SimBaseListener {Symbols = symbolFile}; 62 | 63 | walker.Walk(sbl, tree); 64 | 65 | Assert.AreEqual(0x11, sbl.Proc.XRegister); 66 | Assert.AreEqual(0x22, sbl.Proc.Accumulator); 67 | Assert.AreEqual(0xff, sbl.Proc.YRegister); 68 | } 69 | 70 | [Test] 71 | public void TestSuite3() 72 | { 73 | var symbols = new Dictionary 74 | { 75 | {"Val1", 0x11}, 76 | {"Val2", 0x22}, 77 | {"Val3", 0xff}, 78 | {"Loc1", 0xd020}, 79 | {"Loc2", 0xd021}, 80 | {"Loc3", 0xd022} 81 | }; 82 | 83 | 84 | var symbolFile = new SymbolFile(symbols); 85 | 86 | var tree = GetContext("GrammarTests/test-3.txt"); 87 | 88 | var walker = new ParseTreeWalker(); 89 | var sbl = new SimBaseListener {Symbols = symbolFile}; 90 | 91 | walker.Walk(sbl, tree); 92 | 93 | Assert.AreEqual(0x11, sbl.Proc.ReadMemoryValueWithoutCycle(0xd020)); 94 | Assert.AreEqual(0x22, sbl.Proc.ReadMemoryValueWithoutCycle(0xd021)); 95 | Assert.AreEqual(0xff, sbl.Proc.ReadMemoryValueWithoutCycle(0xd022)); 96 | } 97 | 98 | [Test] 99 | public void TestSuite4() 100 | { 101 | var symbols = new Dictionary {{"FALSE", 0x00}}; 102 | 103 | var symbolFile = new SymbolFile(symbols); 104 | var tree = GetContext("GrammarTests/test-4.txt"); 105 | 106 | var walker = new ParseTreeWalker(); 107 | var sbl = new SimBaseListener {Symbols = symbolFile}; 108 | 109 | walker.Walk(sbl, tree); 110 | 111 | Assert.IsTrue(sbl.Proc.CarryFlag); 112 | Assert.IsFalse(sbl.Proc.NegativeFlag); 113 | Assert.IsTrue(sbl.Proc.ZeroFlag); 114 | Assert.IsFalse(sbl.Proc.OverflowFlag); 115 | Assert.IsFalse(sbl.Proc.DecimalFlag); 116 | } 117 | 118 | [Test] 119 | public void TestSuite5() 120 | { 121 | var tree = GetContext("GrammarTests/test-5.txt"); 122 | 123 | var walker = new ParseTreeWalker(); 124 | var sbl = new SimBaseListener(); 125 | 126 | walker.Walk(sbl, tree); 127 | } 128 | 129 | [Test] 130 | public void TestSuite6() 131 | { 132 | var tree = GetContext("GrammarTests/test-6.txt"); 133 | 134 | var walker = new ParseTreeWalker(); 135 | var sbl = new SimBaseListener(); 136 | 137 | walker.Walk(sbl, tree); 138 | } 139 | 140 | [Test] 141 | public void TestSuite7() 142 | { 143 | var tree = GetContext("GrammarTests/test-7.txt"); 144 | 145 | var walker = new ParseTreeWalker(); 146 | var sbl = new SimBaseListener(); 147 | 148 | walker.Walk(sbl, tree); 149 | } 150 | 151 | [Test] 152 | public void TestSuite8() 153 | { 154 | var symbols = new Dictionary 155 | { 156 | {"Loc1", 0xd020} 157 | }; 158 | 159 | var symbolFile = new SymbolFile(symbols); 160 | 161 | var tree = GetContext("GrammarTests/test-8.txt"); 162 | 163 | var walker = new ParseTreeWalker(); 164 | var sbl = new SimBaseListener {Symbols = symbolFile}; 165 | 166 | walker.Walk(sbl, tree); 167 | 168 | Assert.AreEqual(0xabcd, sbl.Proc.ReadMemoryWordWithoutCycle(0xd020)); 169 | Assert.AreEqual(0xd0, sbl.Proc.ReadMemoryValueWithoutCycle(0xd022)); 170 | } 171 | 172 | [Test] 173 | public void TestSuite9() 174 | { 175 | var symbols = new Dictionary 176 | { 177 | {"Loc1", 0xd020} 178 | }; 179 | 180 | var symbolFile = new SymbolFile(symbols); 181 | 182 | var tree = GetContext("GrammarTests/test-9.txt"); 183 | 184 | var walker = new ParseTreeWalker(); 185 | var sbl = new SimBaseListener {Symbols = symbolFile}; 186 | 187 | walker.Walk(sbl, tree); 188 | } 189 | 190 | [Test] 191 | public void TestSuite10() 192 | { 193 | var symbols = new Dictionary 194 | { 195 | {"Loc1", 0xd020} 196 | }; 197 | 198 | var symbolFile = new SymbolFile(symbols); 199 | 200 | var tree = GetContext("GrammarTests/test-10.txt"); 201 | 202 | var walker = new ParseTreeWalker(); 203 | var sbl = new SimBaseListener {Symbols = symbolFile}; 204 | 205 | walker.Walk(sbl, tree); 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /sim6502tests/UtilityTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using sim6502; 3 | using sim6502.Utilities; 4 | 5 | namespace sim6502tests 6 | { 7 | [TestFixture] 8 | public class UtilityTests 9 | { 10 | [Test] 11 | public void TestParseHexWithDollarSign() 12 | { 13 | var hex1 = "$ffff"; 14 | Assert.AreEqual(0xffff.ToString(), hex1.ParseNumber().ToString()); 15 | 16 | hex1 = "$fff"; 17 | Assert.AreEqual(0xfff.ToString(), hex1.ParseNumber().ToString()); 18 | 19 | hex1 = "$ff"; 20 | Assert.AreEqual(0xff.ToString(), hex1.ParseNumber().ToString()); 21 | 22 | hex1 = "$f"; 23 | Assert.AreEqual(0xf.ToString(), hex1.ParseNumber().ToString()); 24 | 25 | hex1 = "$abcd"; 26 | Assert.AreEqual(0xabcd.ToString(), hex1.ParseNumber().ToString()); 27 | } 28 | 29 | [Test] 30 | public void TestParseWithZeroX() 31 | { 32 | var hex1 = "0xffff"; 33 | Assert.AreEqual(0xffff.ToString(), hex1.ParseNumber().ToString()); 34 | 35 | hex1 = "0xfff"; 36 | Assert.AreEqual(0xfff.ToString(), hex1.ParseNumber().ToString()); 37 | 38 | hex1 = "0xff"; 39 | Assert.AreEqual(0xff.ToString(), hex1.ParseNumber().ToString()); 40 | 41 | hex1 = "0xf"; 42 | Assert.AreEqual(0xf.ToString(), hex1.ParseNumber().ToString()); 43 | 44 | hex1 = "0xabcd"; 45 | Assert.AreEqual(0xabcd.ToString(), hex1.ParseNumber().ToString()); 46 | } 47 | 48 | [Test] 49 | public void TestPlainIntegers() 50 | { 51 | var int1 = "65535"; 52 | Assert.AreEqual(0xffff.ToString(), int1.ParseNumber().ToString()); 53 | 54 | int1 = "4095"; 55 | Assert.AreEqual(0xfff.ToString(), int1.ParseNumber().ToString()); 56 | 57 | int1 = "255"; 58 | Assert.AreEqual(0xff.ToString(), int1.ParseNumber().ToString()); 59 | 60 | int1 = "15"; 61 | Assert.AreEqual(0xf.ToString(), int1.ParseNumber().ToString()); 62 | 63 | int1 = "43981"; 64 | Assert.AreEqual(0xabcd.ToString(), int1.ParseNumber().ToString()); 65 | } 66 | 67 | [Test] 68 | public void TestGetLoadAddress() 69 | { 70 | var bytes = new byte[2]; 71 | bytes[0] = 0; 72 | bytes[1] = 192; 73 | 74 | var address = Utility.GetProgramLoadAddress(bytes); 75 | Assert.AreEqual(0xc000.ToString(), address.ToString()); 76 | } 77 | 78 | [Test] 79 | public void TestConvertIntToHex() 80 | { 81 | var i = 65535; 82 | Assert.AreEqual("$ffff", i.ToHex()); 83 | 84 | i = 4095; 85 | Assert.AreEqual("$fff", i.ToHex()); 86 | 87 | i = 255; 88 | Assert.AreEqual("$ff", i.ToHex()); 89 | 90 | i = 15; 91 | Assert.AreEqual("$f", i.ToHex()); 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /sim6502tests/nlog.config: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /sim6502tests/sim6502tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Always 23 | 24 | 25 | Always 26 | 27 | 28 | Always 29 | 30 | 31 | Always 32 | 33 | 34 | Always 35 | 36 | 37 | Always 38 | 39 | 40 | Always 41 | 42 | 43 | Always 44 | 45 | 46 | Always 47 | 48 | 49 | Always 50 | 51 | 52 | Always 53 | 54 | 55 | Always 56 | 57 | 58 | Always 59 | 60 | 61 | 62 | 63 | --------------------------------------------------------------------------------