First commit
This commit is contained in:
		
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | .phpdoc/ | ||||||
|  | .phplint.cache/ | ||||||
|  | .phpunit.cache/ | ||||||
|  | output/ | ||||||
|  | vendor/ | ||||||
							
								
								
									
										50
									
								
								.phpcs.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								.phpcs.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | <?xml version="1.0"?> | ||||||
|  | <ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="PHP_CodeSniffer" xsi:noNamespaceSchemaLocation="phpcs.xsd"> | ||||||
|  |     <description>Coding standard</description> | ||||||
|  |  | ||||||
|  |     <file>src/</file> | ||||||
|  |  | ||||||
|  |     <rule ref="PSR1"> | ||||||
|  |         <exclude name="Generic.Files.LineLength"/> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="PSR2"></rule> | ||||||
|  |     <rule ref="PSR12"></rule> | ||||||
|  |  | ||||||
|  |     <rule ref="Generic"> | ||||||
|  |         <exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed"/> | ||||||
|  |         <exclude name="Generic.Files.LowercasedFilename.NotFound"/> | ||||||
|  |         <exclude name="Generic.PHP.ClosingPHPTag.NotFound"/> | ||||||
|  |         <exclude name="Generic.Files.EndFileNoNewline.Found"/> | ||||||
|  |         <exclude name="Generic.Files.EndFileNoNewline.Found"/> | ||||||
|  |         <exclude name="Generic.Arrays.DisallowShortArraySyntax.Found"/> | ||||||
|  |         <exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine"/> | ||||||
|  |         <exclude name="Generic.Classes.OpeningBraceSameLine.BraceOnNewLine"/> | ||||||
|  |         <exclude name="Generic.PHP.LowerCaseConstant.Found"/> | ||||||
|  |         <exclude name="Generic.Formatting.SpaceAfterCast"/> | ||||||
|  |         <exclude name="Generic.Formatting.MultipleStatementAlignment.NotSameWarning"/> | ||||||
|  |         <exclude name="Generic.Commenting.DocComment.MissingShort"/> | ||||||
|  |         <exclude name="Generic.NamingConventions.AbstractClassNamePrefix.Missing"/> | ||||||
|  |         <exclude name="Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed"/> | ||||||
|  |         <exclude name="Generic.NamingConventions.InterfaceNameSuffix.Missing"/> | ||||||
|  |         <exclude name="Generic.Commenting.Todo.TaskFound"/> | ||||||
|  |         <exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUse"/> | ||||||
|  |         <exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassAfterLastUsed"/> | ||||||
|  |         <exclude name="Generic.CodeAnalysis.UnusedFunctionParameter.FoundInImplementedInterfaceAfterLastUsed"/> | ||||||
|  |         <exclude name="Generic.Formatting.SpaceBeforeCast.NoSpace"/> | ||||||
|  |         <exclude name="Generic.CodeAnalysis.UselessOverridingMethod.Found"/> | ||||||
|  |         <exclude name="Squiz.Functions.MultiLineFunctionDeclaration.NewlineBeforeOpenBrace"/> | ||||||
|  |     </rule> | ||||||
|  |  | ||||||
|  |     <!-- Ban some functions --> | ||||||
|  |     <rule ref="Generic.PHP.ForbiddenFunctions"> | ||||||
|  |         <properties> | ||||||
|  |             <property name="forbiddenFunctions" type="array"> | ||||||
|  |                 <element key="sizeof" value="count"/> | ||||||
|  |                 <element key="delete" value="unset"/> | ||||||
|  |                 <element key="print" value="echo"/> | ||||||
|  |                 <element key="is_null" value="null"/> | ||||||
|  |                 <element key="create_function" value="null"/> | ||||||
|  |             </property> | ||||||
|  |         </properties> | ||||||
|  |     </rule> | ||||||
|  | </ruleset> | ||||||
							
								
								
									
										0
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										7
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | SIMAVRPHP | ||||||
|  | ========== | ||||||
|  |  | ||||||
|  |  | ||||||
|  | What | ||||||
|  | ----- | ||||||
|  | Implementing an ATmega328p simulator in PHP. Just because. | ||||||
							
								
								
									
										20
									
								
								bin/simavr.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								bin/simavr.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  | require_once("vendor/autoload.php"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | use Monolog\Level; | ||||||
|  | use Monolog\Logger; | ||||||
|  | use Monolog\Handler\StreamHandler; | ||||||
|  | use Monolog\Handler\FirePHPHandler; | ||||||
|  |  | ||||||
|  | // Create the logger | ||||||
|  | $logger = new Logger('simavrphp'); | ||||||
|  | // Now add some handlers | ||||||
|  | $logger->pushHandler(new StreamHandler('php://stderr')); | ||||||
|  |  | ||||||
|  | $avr = new SimAVRPHP\AVR($logger); | ||||||
|  | $mem = file_get_contents($argv[1]); | ||||||
|  | $avr->setMemory($mem); | ||||||
|  | while(true){ | ||||||
|  |     $avr->step(); | ||||||
|  | } | ||||||
							
								
								
									
										48
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | { | ||||||
|  |     "require": { | ||||||
|  |         "php": "^8.3", | ||||||
|  |         "monolog/monolog": "^3.7" | ||||||
|  |       }, | ||||||
|  |     "require-dev": { | ||||||
|  |         "vimeo/psalm": "^5.15", | ||||||
|  |         "phpstan/phpstan": "^1.10", | ||||||
|  |         "phpunit/phpunit": "^10.3", | ||||||
|  |         "phpmetrics/phpmetrics": "^2.8", | ||||||
|  |         "rector/rector": "^1.2" | ||||||
|  |     }, | ||||||
|  |     "autoload": { | ||||||
|  |         "psr-4": { | ||||||
|  |             "SimAVRPHP\\": "src/" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "scripts": { | ||||||
|  |         "test":          "phpunit", | ||||||
|  |         "document":      "phpDocumentor", | ||||||
|  |         "benchmark":     "phpbench run --report=default --output=build-artifact", | ||||||
|  |         "metrics":       "vendor/bin/phpmetrics --config=phpmetrics.json", | ||||||
|  |         "lint": [ | ||||||
|  |             "phplint", | ||||||
|  |             "phpcs", | ||||||
|  |             "phpmd src/,tests/ text phpmd.ruleset.xml" | ||||||
|  |         ], | ||||||
|  |         "analyze": [ | ||||||
|  |             "@analyze-phpstan", | ||||||
|  |             "@analyze-psalm", | ||||||
|  |             "@analyze-rector" | ||||||
|  |         ], | ||||||
|  |         "analyze-phpstan":"vendor/bin/phpstan analyze --error-format=raw", | ||||||
|  |         "analyze-psalm":  "vendor/bin/psalm --no-cache --show-info=true", | ||||||
|  |         "analyze-rector": "vendor/bin/rector --dry-run", | ||||||
|  |         "html": [ | ||||||
|  |           "pandoc -s README.md -o output/README.html" | ||||||
|  |         ], | ||||||
|  |         "all": [ | ||||||
|  |           "@test", | ||||||
|  |           "@lint", | ||||||
|  |           "@analyze", | ||||||
|  |           "@document", | ||||||
|  |           "@metrics", | ||||||
|  |           "@html" | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  | } | ||||||
							
								
								
									
										3880
									
								
								composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										3880
									
								
								composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								composer.phar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								composer.phar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										20
									
								
								phpdoc.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								phpdoc.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" ?> | ||||||
|  | <phpdocumentor | ||||||
|  |         configVersion="3" | ||||||
|  |         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |         xmlns="https://www.phpdoc.org" | ||||||
|  |         xsi:noNamespaceSchemaLocation="https://docs.phpdoc.org/latest/phpdoc.xsd" | ||||||
|  | > | ||||||
|  |     <title>trueskill</title> | ||||||
|  |     <paths> | ||||||
|  |         <output>output/docs</output> | ||||||
|  |     </paths> | ||||||
|  |     <version number="latest"> | ||||||
|  |         <api> | ||||||
|  |             <source> | ||||||
|  |                 <path>src</path> | ||||||
|  |             </source> | ||||||
|  |         </api> | ||||||
|  |     </version> | ||||||
|  |     <!--setting name="graphs.enabled" value="true"/--> | ||||||
|  | </phpdocumentor> | ||||||
							
								
								
									
										47
									
								
								phpmd.ruleset.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								phpmd.ruleset.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | <?xml version="1.0"?> | ||||||
|  | <ruleset name="Custom PHPMD rules" | ||||||
|  |          xmlns="http://pmd.sf.net/ruleset/1.0.0" | ||||||
|  |          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |          xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 | ||||||
|  |                      http://pmd.sf.net/ruleset_xml_schema.xsd" | ||||||
|  |          xsi:noNamespaceSchemaLocation=" | ||||||
|  |                      http://pmd.sf.net/ruleset_xml_schema.xsd"> | ||||||
|  |     <description> | ||||||
|  |         Custom PHPMD rules | ||||||
|  |     </description> | ||||||
|  |  | ||||||
|  |     <rule ref="rulesets/cleancode.xml"> | ||||||
|  |         <exclude name="StaticAccess" /> | ||||||
|  |         <exclude name="ElseExpression" /> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="rulesets/codesize.xml" > | ||||||
|  |         <exclude name="TooManyMethods" /> | ||||||
|  |         <exclude name="TooManyPublicMethods" /> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="rulesets/codesize.xml/TooManyMethods"> | ||||||
|  |         <priority>1</priority> | ||||||
|  |         <properties> | ||||||
|  |             <property name="ignorepattern" value="#^(set|get|test)|test$#i" /> | ||||||
|  |         </properties> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="rulesets/codesize.xml/TooManyPublicMethods"> | ||||||
|  |         <priority>1</priority> | ||||||
|  |         <properties> | ||||||
|  |             <property name="ignorepattern" value="#^(set|get|test)|test$#i" /> | ||||||
|  |         </properties> | ||||||
|  |     </rule> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     <rule ref="rulesets/design.xml" /> | ||||||
|  |     <rule ref="rulesets/naming.xml" > | ||||||
|  |         <exclude name="LongClassName" /> | ||||||
|  |         <exclude name="ShortClassName" /> | ||||||
|  |         <exclude name="ShortVariable" /> | ||||||
|  |         <exclude name="LongVariable" /> | ||||||
|  |         <exclude name="ShortMethodName" /> | ||||||
|  |     </rule> | ||||||
|  |     <rule ref="rulesets/unusedcode.xml" /> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </ruleset> | ||||||
							
								
								
									
										21
									
								
								phpmetrics.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								phpmetrics.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | { | ||||||
|  |     "composer": true, | ||||||
|  |     "includes": [ | ||||||
|  |       "src" | ||||||
|  |     ], | ||||||
|  |     "excludes": [ | ||||||
|  |       "tests" | ||||||
|  |     ], | ||||||
|  |     "report": { | ||||||
|  |       "html": "output/metrics/", | ||||||
|  |       "json": "output/metrics/report.json" | ||||||
|  |     }, | ||||||
|  |     "plugins": { | ||||||
|  |       "git": { | ||||||
|  |         "binary": "git" | ||||||
|  |       }, | ||||||
|  |       "junit": { | ||||||
|  |         "file": "output/test.xml" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										5
									
								
								phpstan.neon
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								phpstan.neon
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | parameters: | ||||||
|  | 	level: 6 | ||||||
|  | 	paths: | ||||||
|  | 		- src | ||||||
|  | 		- tests | ||||||
							
								
								
									
										24
									
								
								phpunit.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								phpunit.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" cacheDirectory=".phpunit.cache" backupStaticProperties="false"  displayDetailsOnTestsThatTriggerWarnings="true" beStrictAboutCoverageMetadata="true" requireCoverageMetadata="true"> | ||||||
|  |   <testsuites> | ||||||
|  |     <testsuite name="Test Suite"> | ||||||
|  |       <directory>./tests/</directory> | ||||||
|  |     </testsuite> | ||||||
|  |   </testsuites> | ||||||
|  |   <source> | ||||||
|  |     <include> | ||||||
|  |       <directory suffix=".php">src/</directory> | ||||||
|  |     </include> | ||||||
|  |   </source> | ||||||
|  |   <logging> | ||||||
|  |     <junit outputFile="output/test/junit.xml"/> | ||||||
|  |     <testdoxHtml outputFile="output/test/index.html"/> | ||||||
|  |   </logging> | ||||||
|  |  | ||||||
|  |   <coverage> | ||||||
|  |     <report> | ||||||
|  |       <html outputDirectory="output/coverage" /> | ||||||
|  |       <clover outputFile ="output/coverage/clover.xml" /> | ||||||
|  |     </report> | ||||||
|  |   </coverage> | ||||||
|  | </phpunit> | ||||||
							
								
								
									
										18
									
								
								psalm.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								psalm.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | <?xml version="1.0"?> | ||||||
|  | <psalm | ||||||
|  |     errorLevel="3" | ||||||
|  |     resolveFromConfigFile="true" | ||||||
|  |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |     xmlns="https://getpsalm.org/schema/config" | ||||||
|  |     xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" | ||||||
|  |     findUnusedBaselineEntry="true" | ||||||
|  |     findUnusedCode="false" | ||||||
|  | > | ||||||
|  |     <projectFiles> | ||||||
|  |         <directory name="src" /> | ||||||
|  |         <ignoreFiles> | ||||||
|  |             <directory name="vendor" /> | ||||||
|  |         </ignoreFiles> | ||||||
|  |         <file name="bin/simavr.php" /> | ||||||
|  |     </projectFiles> | ||||||
|  | </psalm> | ||||||
							
								
								
									
										18
									
								
								rector.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								rector.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | use Rector\Config\RectorConfig; | ||||||
|  | use Rector\CodeQuality\Rector\ClassMethod\LocallyCalledStaticMethodToNonStaticRector; | ||||||
|  |  | ||||||
|  | return RectorConfig::configure() | ||||||
|  |     ->withPaths([ | ||||||
|  |         __DIR__ . '/src', | ||||||
|  |         __DIR__ . '/tests', | ||||||
|  |     ]) | ||||||
|  |     // uncomment to reach your current PHP version | ||||||
|  |     ->withPhpSets() | ||||||
|  |     ->withPreparedSets(deadCode: true, codeQuality: true, codingStyle: true, typeDeclarations : true, privatization: true, naming: false, instanceOf: true, earlyReturn: true, strictBooleans: true) | ||||||
|  |     ->withSkip([ | ||||||
|  |         LocallyCalledStaticMethodToNonStaticRector::class | ||||||
|  |     ]);; | ||||||
							
								
								
									
										
											BIN
										
									
								
								resources/blinky/blink.bin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resources/blinky/blink.bin
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										17
									
								
								resources/blinky/blink.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								resources/blinky/blink.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | #ifndef F_CPU | ||||||
|  | #define F_CPU 1000000UL | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <avr/io.h> | ||||||
|  | #include <util/delay.h> | ||||||
|  |  | ||||||
|  | int main(void) { | ||||||
|  |   DDRB = 0b00000001; | ||||||
|  |  | ||||||
|  |   while (1) { | ||||||
|  |     PORTB = 0b00000001; | ||||||
|  |     PORTB = 0b00000000; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								resources/blinky/blink.dump
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								resources/blinky/blink.dump
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  |  | ||||||
|  | blink.elf:     file format elf32-avr | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Disassembly of section .text: | ||||||
|  |  | ||||||
|  | 00000000 <__vectors>: | ||||||
|  |    0:	0c 94 34 00 	jmp	0x68	; 0x68 <__ctors_end> | ||||||
|  |    4:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |    8:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |    c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   10:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   14:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   18:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   1c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   20:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   24:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   28:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   2c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   30:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   34:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   38:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   3c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   40:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   44:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   48:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   4c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   50:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   54:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   58:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   5c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   60:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   64:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |  | ||||||
|  | 00000068 <__ctors_end>: | ||||||
|  |   68:	11 24       	eor	r1, r1 | ||||||
|  |   6a:	1f be       	out	0x3f, r1	; 63 | ||||||
|  |   6c:	cf ef       	ldi	r28, 0xFF	; 255 | ||||||
|  |   6e:	d8 e0       	ldi	r29, 0x08	; 8 | ||||||
|  |   70:	de bf       	out	0x3e, r29	; 62 | ||||||
|  |   72:	cd bf       	out	0x3d, r28	; 61 | ||||||
|  |   74:	0e 94 40 00 	call	0x80	; 0x80 <main> | ||||||
|  |   78:	0c 94 45 00 	jmp	0x8a	; 0x8a <_exit> | ||||||
|  |  | ||||||
|  | 0000007c <__bad_interrupt>: | ||||||
|  |   7c:	0c 94 00 00 	jmp	0	; 0x0 <__vectors> | ||||||
|  |  | ||||||
|  | 00000080 <main>: | ||||||
|  |  | ||||||
|  | #include <avr/io.h> | ||||||
|  | #include <util/delay.h> | ||||||
|  |  | ||||||
|  | int main(void) { | ||||||
|  |   DDRB = 0b00000001; | ||||||
|  |   80:	81 e0       	ldi	r24, 0x01	; 1 | ||||||
|  |   82:	84 b9       	out	0x04, r24	; 4 | ||||||
|  |  | ||||||
|  |   while (1) { | ||||||
|  |     PORTB = 0b00000001; | ||||||
|  |   84:	85 b9       	out	0x05, r24	; 5 | ||||||
|  |     PORTB = 0b00000000; | ||||||
|  |   86:	15 b8       	out	0x05, r1	; 5 | ||||||
|  |   88:	fd cf       	rjmp	.-6      	; 0x84 <main+0x4> | ||||||
|  |  | ||||||
|  | 0000008a <_exit>: | ||||||
|  |   8a:	f8 94       	cli | ||||||
|  |  | ||||||
|  | 0000008c <__stop_program>: | ||||||
|  |   8c:	ff cf       	rjmp	.-2      	; 0x8c <__stop_program> | ||||||
							
								
								
									
										
											BIN
										
									
								
								resources/blinky/blink.elf
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resources/blinky/blink.elf
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										10
									
								
								resources/blinky/blink.hex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								resources/blinky/blink.hex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | :100000000C9434000C943E000C943E000C943E0082 | ||||||
|  | :100010000C943E000C943E000C943E000C943E0068 | ||||||
|  | :100020000C943E000C943E000C943E000C943E0058 | ||||||
|  | :100030000C943E000C943E000C943E000C943E0048 | ||||||
|  | :100040000C943E000C943E000C943E000C943E0038 | ||||||
|  | :100050000C943E000C943E000C943E000C943E0028 | ||||||
|  | :100060000C943E000C943E0011241FBECFEFD8E04C | ||||||
|  | :10007000DEBFCDBF0E9440000C9445000C940000F0 | ||||||
|  | :0E00800081E084B985B915B8FDCFF894FFCFA3 | ||||||
|  | :00000001FF | ||||||
							
								
								
									
										
											BIN
										
									
								
								resources/blinky/blink.o
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resources/blinky/blink.o
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										7
									
								
								resources/blinky/compile.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								resources/blinky/compile.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | avr-gcc -g -Os -mmcu=atmega328p -c blink.c | ||||||
|  | avr-gcc -g -mmcu=atmega328p -o blink.elf blink.o | ||||||
|  | avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex | ||||||
|  | avr-size --format=avr --mcu=atmega328p blink.elf | ||||||
|  | objcopy --input-target=ihex --output-target=binary blink.hex blink.bin | ||||||
|  | avr-objdump -d -S -m avr5 blink.elf > blink.dump | ||||||
							
								
								
									
										
											BIN
										
									
								
								resources/blinky2/blink.bin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resources/blinky2/blink.bin
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										19
									
								
								resources/blinky2/blink.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								resources/blinky2/blink.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | #ifndef F_CPU | ||||||
|  | #define F_CPU 1000000UL | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <avr/io.h> | ||||||
|  | #include <util/delay.h> | ||||||
|  |  | ||||||
|  | int main(void) { | ||||||
|  |   DDRB = 0b00000001; | ||||||
|  |  | ||||||
|  |   while (1) { | ||||||
|  |     PORTB = 0b00000001; | ||||||
|  |     _delay_ms(500); | ||||||
|  |     PORTB = 0b00000000; | ||||||
|  |     _delay_ms(500); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
							
								
								
									
										94
									
								
								resources/blinky2/blink.dump
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								resources/blinky2/blink.dump
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  |  | ||||||
|  | blink.elf:     file format elf32-avr | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Disassembly of section .text: | ||||||
|  |  | ||||||
|  | 00000000 <__vectors>: | ||||||
|  |    0:	0c 94 34 00 	jmp	0x68	; 0x68 <__ctors_end> | ||||||
|  |    4:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |    8:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |    c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   10:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   14:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   18:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   1c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   20:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   24:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   28:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   2c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   30:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   34:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   38:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   3c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   40:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   44:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   48:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   4c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   50:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   54:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   58:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   5c:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   60:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |   64:	0c 94 3e 00 	jmp	0x7c	; 0x7c <__bad_interrupt> | ||||||
|  |  | ||||||
|  | 00000068 <__ctors_end>: | ||||||
|  |   68:	11 24       	eor	r1, r1 | ||||||
|  |   6a:	1f be       	out	0x3f, r1	; 63 | ||||||
|  |   6c:	cf ef       	ldi	r28, 0xFF	; 255 | ||||||
|  |   6e:	d8 e0       	ldi	r29, 0x08	; 8 | ||||||
|  |   70:	de bf       	out	0x3e, r29	; 62 | ||||||
|  |   72:	cd bf       	out	0x3d, r28	; 61 | ||||||
|  |   74:	0e 94 40 00 	call	0x80	; 0x80 <main> | ||||||
|  |   78:	0c 94 57 00 	jmp	0xae	; 0xae <_exit> | ||||||
|  |  | ||||||
|  | 0000007c <__bad_interrupt>: | ||||||
|  |   7c:	0c 94 00 00 	jmp	0	; 0x0 <__vectors> | ||||||
|  |  | ||||||
|  | 00000080 <main>: | ||||||
|  |  | ||||||
|  | #include <avr/io.h> | ||||||
|  | #include <util/delay.h> | ||||||
|  |  | ||||||
|  | int main(void) { | ||||||
|  |   DDRB = 0b00000001; | ||||||
|  |   80:	81 e0       	ldi	r24, 0x01	; 1 | ||||||
|  |   82:	84 b9       	out	0x04, r24	; 4 | ||||||
|  |  | ||||||
|  |   while (1) { | ||||||
|  |     PORTB = 0b00000001; | ||||||
|  |   84:	85 b9       	out	0x05, r24	; 5 | ||||||
|  | 	#else | ||||||
|  | 		//round up by default | ||||||
|  | 		__ticks_dc = (uint32_t)(ceil(fabs(__tmp))); | ||||||
|  | 	#endif | ||||||
|  |  | ||||||
|  | 	__builtin_avr_delay_cycles(__ticks_dc); | ||||||
|  |   86:	2f e9       	ldi	r18, 0x9F	; 159 | ||||||
|  |   88:	36 e8       	ldi	r19, 0x86	; 134 | ||||||
|  |   8a:	91 e0       	ldi	r25, 0x01	; 1 | ||||||
|  |   8c:	21 50       	subi	r18, 0x01	; 1 | ||||||
|  |   8e:	30 40       	sbci	r19, 0x00	; 0 | ||||||
|  |   90:	90 40       	sbci	r25, 0x00	; 0 | ||||||
|  |   92:	e1 f7       	brne	.-8      	; 0x8c <main+0xc> | ||||||
|  |   94:	00 c0       	rjmp	.+0      	; 0x96 <main+0x16> | ||||||
|  |   96:	00 00       	nop | ||||||
|  |     _delay_ms(500); | ||||||
|  |     PORTB = 0b00000000; | ||||||
|  |   98:	15 b8       	out	0x05, r1	; 5 | ||||||
|  |   9a:	2f e9       	ldi	r18, 0x9F	; 159 | ||||||
|  |   9c:	36 e8       	ldi	r19, 0x86	; 134 | ||||||
|  |   9e:	91 e0       	ldi	r25, 0x01	; 1 | ||||||
|  |   a0:	21 50       	subi	r18, 0x01	; 1 | ||||||
|  |   a2:	30 40       	sbci	r19, 0x00	; 0 | ||||||
|  |   a4:	90 40       	sbci	r25, 0x00	; 0 | ||||||
|  |   a6:	e1 f7       	brne	.-8      	; 0xa0 <main+0x20> | ||||||
|  |   a8:	00 c0       	rjmp	.+0      	; 0xaa <main+0x2a> | ||||||
|  |   aa:	00 00       	nop | ||||||
|  |   ac:	eb cf       	rjmp	.-42     	; 0x84 <main+0x4> | ||||||
|  |  | ||||||
|  | 000000ae <_exit>: | ||||||
|  |   ae:	f8 94       	cli | ||||||
|  |  | ||||||
|  | 000000b0 <__stop_program>: | ||||||
|  |   b0:	ff cf       	rjmp	.-2      	; 0xb0 <__stop_program> | ||||||
							
								
								
									
										
											BIN
										
									
								
								resources/blinky2/blink.elf
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resources/blinky2/blink.elf
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										13
									
								
								resources/blinky2/blink.hex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								resources/blinky2/blink.hex
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | :100000000C9434000C943E000C943E000C943E0082 | ||||||
|  | :100010000C943E000C943E000C943E000C943E0068 | ||||||
|  | :100020000C943E000C943E000C943E000C943E0058 | ||||||
|  | :100030000C943E000C943E000C943E000C943E0048 | ||||||
|  | :100040000C943E000C943E000C943E000C943E0038 | ||||||
|  | :100050000C943E000C943E000C943E000C943E0028 | ||||||
|  | :100060000C943E000C943E0011241FBECFEFD8E04C | ||||||
|  | :10007000DEBFCDBF0E9440000C9457000C940000DE | ||||||
|  | :1000800081E084B985B92FE936E891E0215030400C | ||||||
|  | :100090009040E1F700C0000015B82FE936E891E084 | ||||||
|  | :1000A000215030409040E1F700C00000EBCFF894C1 | ||||||
|  | :0200B000FFCF80 | ||||||
|  | :00000001FF | ||||||
							
								
								
									
										
											BIN
										
									
								
								resources/blinky2/blink.o
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								resources/blinky2/blink.o
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										7
									
								
								resources/blinky2/compile.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								resources/blinky2/compile.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | avr-gcc -g -Os -mmcu=atmega328p -c blink.c | ||||||
|  | avr-gcc -g -mmcu=atmega328p -o blink.elf blink.o | ||||||
|  | avr-objcopy -j .text -j .data -O ihex blink.elf blink.hex | ||||||
|  | avr-size --format=avr --mcu=atmega328p blink.elf | ||||||
|  | avr-objcopy --input-target=ihex --output-target=binary blink.hex blink.bin | ||||||
|  | avr-objdump -d -S -m avr5 blink.elf > blink.dump | ||||||
							
								
								
									
										59
									
								
								src/AVR.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/AVR.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP; | ||||||
|  |  | ||||||
|  | use SimAVRPHP\Exceptions\InvalidAddressException; | ||||||
|  | use Psr\Log\LoggerInterface; | ||||||
|  |  | ||||||
|  | class AVR | ||||||
|  | { | ||||||
|  |     public ProgramCounter $pc; | ||||||
|  |  | ||||||
|  |     public Registers $registers; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var Stack Contains the CPU stack | ||||||
|  |      */ | ||||||
|  |     public Stack $stack; | ||||||
|  |  | ||||||
|  |     public string $memory = ""; | ||||||
|  |  | ||||||
|  |     public function __construct(public LoggerInterface $logger) | ||||||
|  |     { | ||||||
|  |         $this->pc = new ProgramCounter(); | ||||||
|  |         $this->registers = new Registers(); | ||||||
|  |         $this->stack = new Stack(); | ||||||
|  |         $this->reset(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setMemory(string $memory): void | ||||||
|  |     { | ||||||
|  |         $this->memory = $memory; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function reset(): void | ||||||
|  |     { | ||||||
|  |         $this->pc->reset(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function step(): void | ||||||
|  |     { | ||||||
|  |         $rawOperation = $this->getOperation(); | ||||||
|  |         $operation = Opcode\Instruction::createInstructionFromOpcode($this, $rawOperation); | ||||||
|  |  | ||||||
|  |         $this->logger->debug("Prepare instruction for execution", ['PC' => $this->pc->get(), 'Class' => $operation::class]); | ||||||
|  |         $operation->execute(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private function getOperation(): string | ||||||
|  |     { | ||||||
|  |         $opcode = unpack("v2", $this->memory, $this->pc->get()); | ||||||
|  |         if ($opcode == FALSE) { | ||||||
|  |             throw new InvalidAddressException(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return str_pad(decbin((int)$opcode[1]), 16, "0", STR_PAD_LEFT) . str_pad(decbin((int)$opcode[2]), 16, "0", STR_PAD_LEFT); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								src/Exceptions/InvalidAddressException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Exceptions/InvalidAddressException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Exceptions; | ||||||
|  |  | ||||||
|  | use Exception; | ||||||
|  |  | ||||||
|  | class InvalidAddressException extends Exception | ||||||
|  | { | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								src/Exceptions/UnsupportedInstructionException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/Exceptions/UnsupportedInstructionException.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Exceptions; | ||||||
|  |  | ||||||
|  | use Exception; | ||||||
|  |  | ||||||
|  | class UnsupportedInstructionException extends Exception | ||||||
|  | { | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								src/Opcode/BRNE.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/Opcode/BRNE.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class BRNE extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "111101kkkkkkk001"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public function do(int $k): void | ||||||
|  |     { | ||||||
|  |         $k = Instruction::signed($k, -64, 63); | ||||||
|  |         $this->debug('Branch if Not Equal: ' . $k); | ||||||
|  |         $return_address = $this->mcu->pc->get() + (self::WORDS << 1); | ||||||
|  |         $this->mcu->stack->push($return_address); | ||||||
|  |  | ||||||
|  |         $newPC = $this->mcu->pc->get(); | ||||||
|  |         if ($this->mcu->registers->getZ()) { | ||||||
|  |             $newPC += (self::WORDS << 1); | ||||||
|  |         } else { | ||||||
|  |             $newPC += ($k << 1) + 2; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->mcu->pc->jump($newPC); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								src/Opcode/CALL.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/Opcode/CALL.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class CALL extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "1001010kkkkk111kkkkkkkkkkkkkkkkk"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 2; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 4; | ||||||
|  |  | ||||||
|  |     public function do(int $k): void | ||||||
|  |     { | ||||||
|  |         $this->debug("Call", ['k' => $k]); | ||||||
|  |         $return_address = $this->mcu->pc->get() + (self::WORDS << 1); | ||||||
|  |         $this->mcu->stack->push($return_address); | ||||||
|  |         $this->mcu->pc->jump($k << 1); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								src/Opcode/CLI.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Opcode/CLI.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class CLI extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "1001010011111000"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 1; | ||||||
|  |  | ||||||
|  |     public function do(): void | ||||||
|  |     { | ||||||
|  |         $this->mcu->registers->setI(FALSE); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								src/Opcode/EOR.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/Opcode/EOR.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class EOR extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "001001rdddddrrrr"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 1; | ||||||
|  |  | ||||||
|  |     public function do(int $r, int $d): void | ||||||
|  |     { | ||||||
|  |         $Rd = $this->mcu->registers->get($d); | ||||||
|  |         $Rr = $this->mcu->registers->get($r); | ||||||
|  |  | ||||||
|  |         $result = $Rd ^ $Rr; | ||||||
|  |  | ||||||
|  |         $this->mcu->registers->set($d, $result); | ||||||
|  |         $this->debug(sprintf('Exclusive OR: %d xor %d = %d', $Rd, $Rr, $result)); | ||||||
|  |         $this->mcu->pc->stepWords(self::WORDS); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										117
									
								
								src/Opcode/Instruction.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								src/Opcode/Instruction.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | use SimAVRPHP\AVR; | ||||||
|  | use SimAVRPHP\Exceptions\UnsupportedInstructionException; | ||||||
|  | use Exception; | ||||||
|  |  | ||||||
|  | class Instruction | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var class-string[] | ||||||
|  |      */ | ||||||
|  |     protected static $AVRInstructions = [ | ||||||
|  |         \SimAVRPHP\Opcode\BRNE::class, | ||||||
|  |         \SimAVRPHP\Opcode\CALL::class, | ||||||
|  |         \SimAVRPHP\Opcode\CLI::class, | ||||||
|  |         \SimAVRPHP\Opcode\EOR::class, | ||||||
|  |         \SimAVRPHP\Opcode\JMP::class, | ||||||
|  |         \SimAVRPHP\Opcode\LDI::class, | ||||||
|  |         \SimAVRPHP\Opcode\NOP::class, | ||||||
|  |         \SimAVRPHP\Opcode\OUT::class, | ||||||
|  |         \SimAVRPHP\Opcode\RJMP::class, | ||||||
|  |         \SimAVRPHP\Opcode\SBCI::class, | ||||||
|  |         \SimAVRPHP\Opcode\SUBI::class, | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param array<string,int> $operands | ||||||
|  |      */ | ||||||
|  |     protected function __construct(protected AVR $mcu, protected array $operands) | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @return bool|array<string,int> | ||||||
|  |      */ | ||||||
|  |     private static function decode(string $opcode, string $pattern): array|bool | ||||||
|  |     { | ||||||
|  |         $data = []; | ||||||
|  |         $pattern_length = strlen($pattern); | ||||||
|  |         if ($pattern_length != 16 && $pattern_length != 32) { | ||||||
|  |             throw new Exception('Pattern length invalid ' . $pattern_length); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for ($c = 0; $c < $pattern_length; $c++) { | ||||||
|  |             $token = $pattern[$c]; | ||||||
|  |             $instructionBit = $opcode[$c]; | ||||||
|  |             if ($token === "1" || $token === "0") { | ||||||
|  |                 if ($instructionBit !== $token) { | ||||||
|  |                     return FALSE; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 if (! isset($data[$token])) { | ||||||
|  |                     $data[$token] = ""; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 $data[$token] .= $instructionBit; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return array_map( | ||||||
|  |             fn(string $element): int => (int)bindec($element), | ||||||
|  |             $data | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function execute(): void | ||||||
|  |     { | ||||||
|  |         if (is_callable([$this,'do'])) { | ||||||
|  |             call_user_func_array([$this,'do'], $this->operands); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static function createInstructionFromOpcode(AVR $mcu, string $opcode): Instruction | ||||||
|  |     { | ||||||
|  |         foreach (self::$AVRInstructions as $i) { | ||||||
|  |             $data = self::decode($opcode, constant($i . "::OPCODE")); | ||||||
|  |             if ($data !== FALSE) { | ||||||
|  |                 $obj = new $i($mcu, $data); | ||||||
|  |                 if ($obj instanceof Instruction) { | ||||||
|  |                     return $obj; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         throw new UnsupportedInstructionException("Unsupported instruction", (int)bindec($opcode)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param array<string,int> $param | ||||||
|  |      */ | ||||||
|  |     public function debug(string $string, array $param = []): void | ||||||
|  |     { | ||||||
|  |         $this->mcu->logger->debug($string, $param); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function getRegister(int $reg): int | ||||||
|  |     { | ||||||
|  |         return $this->mcu->registers->get($reg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static function signed(int $v, int $min, int $max): int | ||||||
|  |     { | ||||||
|  |         if ($v > $max + abs($min)) { | ||||||
|  |             throw new Exception("Not valid within range"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($v > $max) { | ||||||
|  |             return $min - 1 + $v - $max; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $v; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								src/Opcode/JMP.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/Opcode/JMP.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class JMP extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "1001010kkkkk110kkkkkkkkkkkkkkkkk"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 2; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 3; | ||||||
|  |  | ||||||
|  |     public function do(int $k): void | ||||||
|  |     { | ||||||
|  |         $this->debug("Jump to: " . $k); | ||||||
|  |         $this->mcu->pc->jump($k << 1); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								src/Opcode/LDI.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/Opcode/LDI.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class LDI extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "1110KKKKddddKKKK"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 1; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public function do(int $K, int $d): void | ||||||
|  |     { | ||||||
|  |         $reg = $d + 16; | ||||||
|  |         $this->mcu->registers->set($reg, $K); | ||||||
|  |         $this->debug(sprintf('Load Immediate: %d to R%d', $K, $reg)); | ||||||
|  |         $this->mcu->pc->stepWords(self::WORDS); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								src/Opcode/NOP.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Opcode/NOP.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class NOP extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "0000000000000000"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 1; | ||||||
|  |  | ||||||
|  |     public function do(): void | ||||||
|  |     { | ||||||
|  |         $this->mcu->pc->stepWords(self::WORDS); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								src/Opcode/OUT.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/Opcode/OUT.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class OUT extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "10111AArrrrrAAAA"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 1; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public function do(int $r, int $A): void | ||||||
|  |     { | ||||||
|  |         $Rr = $this->mcu->registers->get($r); | ||||||
|  |  | ||||||
|  |         $this->debug(sprintf('OUT: R%d Value %d to A: %d', $r, $Rr, $A)); | ||||||
|  |         $this->mcu->registers->setA($A, $Rr); | ||||||
|  |         $this->mcu->pc->stepWords(self::WORDS); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								src/Opcode/RJMP.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/Opcode/RJMP.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class RJMP extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "1100kkkkkkkkkkkk"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 2; | ||||||
|  |  | ||||||
|  |     public function do(int $k): void | ||||||
|  |     { | ||||||
|  |         $k = $this->signed($k, -2048, 2047); | ||||||
|  |         $new_pc = $this->mcu->pc->get() + ($k * 2) + 2; | ||||||
|  |         $this->debug("Relative Jump to: " . sprintf("0x%X", $new_pc)); | ||||||
|  |  | ||||||
|  |         $this->mcu->pc->jump($new_pc); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								src/Opcode/SBCI.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/Opcode/SBCI.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class SBCI extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "0100KKKKddddKKKK"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 1; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public function do(int $K, int $d): void | ||||||
|  |     { | ||||||
|  |         $reg = $d + 16; | ||||||
|  |         $value = $this->mcu->registers->get($reg); | ||||||
|  |         $result = $value - $K; | ||||||
|  |         $this->mcu->registers->set($reg, $result); | ||||||
|  |         $this->debug("Subtract Immediate with Carry SBI : R" . $reg . " - " . $K); | ||||||
|  |         $this->mcu->pc->stepWords(self::WORDS); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								src/Opcode/SUBI.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/Opcode/SUBI.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Opcode; | ||||||
|  |  | ||||||
|  | class SUBI extends Instruction | ||||||
|  | { | ||||||
|  |     public const string OPCODE = "0101KKKKddddKKKK"; | ||||||
|  |  | ||||||
|  |     public const int WORDS = 1; | ||||||
|  |  | ||||||
|  |     public const int CYCLES = 1; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public function do(int $K, int $d): void | ||||||
|  |     { | ||||||
|  |         $reg = $d + 16; | ||||||
|  |         $value = $this->mcu->registers->get($reg); | ||||||
|  |         $result = $value - $K; | ||||||
|  |         $this->mcu->registers->set($reg, $result); | ||||||
|  |         $this->debug("Subtract Immediate: R" . $reg . " - " . $K); | ||||||
|  |         $this->mcu->pc->stepWords(self::WORDS); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								src/ProgramCounter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/ProgramCounter.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP; | ||||||
|  |  | ||||||
|  | use SimAVRPHP\Exceptions\InvalidAddressException; | ||||||
|  |  | ||||||
|  | class ProgramCounter | ||||||
|  | { | ||||||
|  |     private const int RESET_PC_VALUE = 0; | ||||||
|  |  | ||||||
|  |     private int $programCounter = self::RESET_PC_VALUE; | ||||||
|  |  | ||||||
|  |     public function get(): int | ||||||
|  |     { | ||||||
|  |         return $this->programCounter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function jump(int $address): void | ||||||
|  |     { | ||||||
|  |         if (($address % 2) != 0) { | ||||||
|  |             throw new InvalidAddressException("Invalid address", $address); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $this->programCounter = $address; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function relativeJump(int $address): void | ||||||
|  |     { | ||||||
|  |         $this->jump($this->programCounter + $address); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function stepWords(int $word): int | ||||||
|  |     { | ||||||
|  |         $this->programCounter += ($word << 1); | ||||||
|  |         return $this->programCounter; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function reset(): void | ||||||
|  |     { | ||||||
|  |         $this->programCounter = self::RESET_PC_VALUE; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								src/Registers.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								src/Registers.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP; | ||||||
|  |  | ||||||
|  | class Registers | ||||||
|  | { | ||||||
|  |     private bool $Z = FALSE; | ||||||
|  |  | ||||||
|  |     private bool $I = FALSE; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var int[] | ||||||
|  |      */ | ||||||
|  |     private $registers = []; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var int[] | ||||||
|  |      */ | ||||||
|  |     private $A = []; | ||||||
|  |  | ||||||
|  |     public function __construct() | ||||||
|  |     { | ||||||
|  |         $this->reset(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function reset(): void | ||||||
|  |     { | ||||||
|  |         $this->Z = FALSE; | ||||||
|  |         $this->I = FALSE; | ||||||
|  |         $this->registers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function get(int $i): int | ||||||
|  |     { | ||||||
|  |         return $this->registers[$i]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function set(int $i, int $value): void | ||||||
|  |     { | ||||||
|  |         $this->registers[$i] = $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setA(int $A, int $value): void | ||||||
|  |     { | ||||||
|  |         $this->A[$A] = $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getA(int $A): int | ||||||
|  |     { | ||||||
|  |         return $this->A[$A]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getZ(): bool | ||||||
|  |     { | ||||||
|  |         return $this->Z; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function setI(bool $I): void | ||||||
|  |     { | ||||||
|  |         $this->$I = $I; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getI(): bool | ||||||
|  |     { | ||||||
|  |         return $this->I; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								src/Stack.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/Stack.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP; | ||||||
|  |  | ||||||
|  | use Exception; | ||||||
|  |  | ||||||
|  | class Stack | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * @var int[] | ||||||
|  |      */ | ||||||
|  |     private array $stack = []; | ||||||
|  |  | ||||||
|  |     public function reset(): void | ||||||
|  |     { | ||||||
|  |         $this->stack = []; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function push(int $value): void | ||||||
|  |     { | ||||||
|  |         $this->stack[] = $value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function pop(): int | ||||||
|  |     { | ||||||
|  |         if (count($this->stack) >= 1) { | ||||||
|  |             return array_pop($this->stack); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         throw new Exception("Stack Underflow"); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								tests/AVRTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								tests/AVRTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Tests; | ||||||
|  |  | ||||||
|  | use SimAVRPHP\AVR; | ||||||
|  |  | ||||||
|  | use Psr\Log\NullLogger; | ||||||
|  |  | ||||||
|  | use PHPUnit\Framework\TestCase; | ||||||
|  | use PHPUnit\Framework\Attributes\CoversClass; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #[CoversClass(AVR::class)] | ||||||
|  | class AVRTest extends TestCase | ||||||
|  | { | ||||||
|  |     public function testStepNOP(): void | ||||||
|  |     { | ||||||
|  |         $avr = new AVR(new NullLogger); | ||||||
|  |         $avr->setMemory("\00\00\00\00"); | ||||||
|  |         $avr->step(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								tests/ProgramCounterTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								tests/ProgramCounterTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | declare(strict_types=1); | ||||||
|  |  | ||||||
|  | namespace SimAVRPHP\Tests; | ||||||
|  |  | ||||||
|  | use SimAVRPHP\ProgramCounter; | ||||||
|  | use SimAVRPHP\Exceptions\InvalidAddressException; | ||||||
|  |  | ||||||
|  | use PHPUnit\Framework\TestCase; | ||||||
|  | use PHPUnit\Framework\Attributes\CoversClass; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #[CoversClass(ProgramCounter::class)] | ||||||
|  | class ProgramCounterTest extends TestCase | ||||||
|  | { | ||||||
|  |     public function testStepAndSet(): void | ||||||
|  |     { | ||||||
|  |         $pc = new ProgramCounter(); | ||||||
|  |         $this->assertEquals(0, $pc->get()); | ||||||
|  |  | ||||||
|  |         $pc->stepWords(1); //Step 1 word | ||||||
|  |  | ||||||
|  |         $this->assertEquals(2, $pc->get()); | ||||||
|  |  | ||||||
|  |         $pc->jump(0x100); | ||||||
|  |         $this->assertEquals(0x100, $pc->get()); | ||||||
|  |  | ||||||
|  |         $pc->reset(); | ||||||
|  |         $this->assertEquals(0, $pc->get()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testSetinvalid(): void | ||||||
|  |     { | ||||||
|  |         $pc = new ProgramCounter(); | ||||||
|  |         $this->expectException(InvalidAddressException::class); | ||||||
|  |         $pc->jump(3); //Uneven address | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user