├── .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 |
4 |
5 |
6 |
7 |
8 |
9 |
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 |
5 |
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 | 
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 |
--------------------------------------------------------------------------------