Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hemanta212/8085-simulator

A simple interpreter for emulating 8085 microprocessor instructions with CLI , REPL and Emacs org-mode interface.
https://github.com/hemanta212/8085-simulator

8085 8085-interpreter 8085-simulator emacs interpreter microprocessor org org-babel org-mode python repl simulator terminal vim

Last synced: 15 days ago
JSON representation

A simple interpreter for emulating 8085 microprocessor instructions with CLI , REPL and Emacs org-mode interface.

Awesome Lists containing this project

README

        

* 8085-Interpreter
#+html:

A simple exploratory interpreter with REPL experience. (Beginning learning purpose only)

- For windows users, you can download and run the =.exe= file from [[https://github.com/hemanta212/8085-simulator/releases/latest][releases page]].
- Clone and run this repository,
#+begin_src shell :eval never
git clone https://github.com/hemanta212/8085-simulator
python -m pip install loguru rich pyreadline
cd 8085-simulator
python main.py
#+end_src

Type =help= and run the commands listed.

For detailed examples on available commands, see file [[file:usage_examples.org]].

** Table of contents
:PROPERTIES:
:TOC: :include siblings :depth 2
:END:
:CONTENTS:
- [[#features][Features]]
- [[#repl-mode][REPL Mode]]
- [[#command-line-arguments][Command line arguments]]
- [[#example-repl-workflow][Example Repl Workflow]]
- [[#example-command-line-workflow][Example Command line Workflow]]
- [[#the-file-option--f][The file option (-f)]]
- [[#the-command-option--c][The command option (-c)]]
- [[#the-json-file-db-option--db][The json file db option (-db)]]
- [[#the-plainindirect-mode-option--i][The plain/indirect mode option (-i)]]
- [[#the-verbosity-logging-option--v][The verbosity logging option (-v)]]
- [[#using-from-terminal-vim-and-emacs][Using From Terminal, Vim and Emacs]]
- [[#example-emacs-org-babel-config][Example Emacs Org babel config]]
- [[#emacs-8085-major-mode][Emacs 8085 major mode]]
- [[#extensive-usage-examples][Extensive Usage Examples]]
:END:

** Features
- [x] - Implement Registers and Memory
- [x] - Implement Basic commands (ADD, ADI, SUB, SUI, MOV, MVI, STA, LDA)
- [x] - Implement Xtended Register Pairs (LXI, M, LDAX)
- [x] - Write a ob-8085 for emacs org-mode (babel)
- [x] - Implement Flags (CY, Z, S)
- [x] - Implement labels and jumps (Loops) [Commands: JC, JNC, JZ, JNZ)
- [x] - Implement increment/decrements [INR, DCR]
- [x] - Implement Xtended increment/decrements [INX, DCX]
- [x] - Implement basic commands (CMP/CPI, OUT)
- [x] - Implement comments, empty lines, HLT(no-effect)
- [x] - Release a pyinstaller executable
- [ ] - Implement commands (ANI, ORI, RRC, STAX)
- [ ] - ... ( a lot of commands)
- [ ] - Implement proper 8-bit 16-bit type system and validation
- [ ] - Implement a stacktrace in case of errors
- [x] - Implement integration test and actions CI
- [ ] - A pypi package
- [-] - Write a major mode for emacs.

** REPL Mode
#+begin_src shell :exports both :results output
python main.py
#+end_src

#+RESULTS:
: Welcome to the 8085 emulator.
: Type 'help' for a list of commands.
: >>>

#+begin_src shell :eval never
>>> help
#+end_src
#+begin_src shell :exports results :results output
echo "help" | python main.py -i
#+end_src

#+RESULTS:
#+begin_example
MOV - Move data from one register to another
MVI - Move to immediate
INR - Increment Register
DCR - Decrement Register
LXI - Load register pair immediate
LDA - Load accumulator
STA - Store accumulator
HLT - Halt
ADD - Add
SUB - Subtract
ADI - Add Immediate
SUI - Subtract Immediate
CMP - Compare
CPI - Compare Immediate
ANI - And Immediate with Accumulator
ORI - OR Immediate with Accumulator
RRC - Rotate Right Accumulator
LDAX - Load accumulator from register pair
STAX - Store accumulator to register pair
INX - Incremented xtended register pairs
DCX - Decrement xtended register pairs
JZ - Jump If Zero
JNZ - Jump If Not Zero
JC - Jump If Carry
JNC - Jump If Not Carry
OUT - Out
#+end_example

** Command line arguments
Beside repl, the interpreter can be entirely run from command line.
#+begin_src shell :exports none :results none
# Cleanup previous eval files if any (during the all eval C-c C-v b)
rm -f /tmp/pyassm-readme-01 /tmp/pyassm-readme-02
#+end_src
#+begin_src shell :exports both :results output :wrap example
python main.py --help
#+end_src

#+RESULTS:
#+begin_example
:8085 Interpreter:

help | --help | -h: Display this message
-i : Run in indirect mode, dont display welcome msg and >>>
prompt
-v : Verbosity option use (d,i,w,e) for (DEBUG, INFO, WARNING,
ERROR) resp.
-db : Run in file db mode save and restore after each cmd from
file
-f : Read command/commands from file
-c "cmd1;cmd2" : Run cmd directly, separate with ";" for more than one
commands

NOTE: In case of using multiple options, they need to be specified in order
listed above.
#+end_example

The interpreter provides:
- An option to run in raw plain mode without any welcome message or =>>>= prompt through =-i= option.
- An option to pass a file (containing commands line by line) to the interpreter to evaluate through =-f= option.
- An option to save state after each command to a json file through =-db= option.
- An option to run commands in place through =-c= option.
- An option to customize the verbosity of logging messages through =-v= option.

*NOTE*:
In case of using multiple options, they need to be specified in order,
- =-i= , =-v=, =-db=, =-f=, =-c=
Providing options otherwise will result in an error.

** Example Repl Workflow
*NOTE* Fore more extensive examples for each commands, see file [[file:usage_examples.org]].

#+begin_src shell :eval never
>>> inspect
#+end_src
#+begin_src shell :exports results :results output
echo "inspect" | python main.py -i
#+end_src

#+RESULTS:
#+begin_example
Registers:
A: 0x00
B: 0x00
C: 0x00
D: 0x00
E: 0x00
H: 0x00
L: 0x00
M: 0x00

Memory:
0x1000: 0x2b
0x1001: 0x34
0x0000: 0x00

Flags:
carry: 0
auxillary_carry: 0
zero: 0
sign: 0
#+end_example

#+begin_src shell :eval never
>>> MVI B 05H
#+end_src
#+begin_src shell :exports results :results output
echo "MVI B 05H" | python main.py -i -db /tmp/pyassm-readme-01
#+end_src

#+RESULTS:
: B -> 05H

#+begin_src shell :eval never
>>> MVI C 05H
#+end_src
#+begin_src shell :exports results :results output
echo "MVI C 05H" | python main.py -i -db /tmp/pyassm-readme-01
#+end_src

#+RESULTS:
: C -> 05H

#+begin_src shell :eval never
>>> ADD B
#+end_src
#+begin_src shell :exports results :results output
echo "ADD B" | python main.py -i -db /tmp/pyassm-readme-01
#+end_src

#+RESULTS:
: A -> 00H + 05H -> 05H

#+begin_src shell :eval never
>>> ADD C
#+end_src
#+begin_src shell :exports results :results output
echo "ADD C" | python main.py -i -db /tmp/pyassm-readme-01
#+end_src

#+RESULTS:
: A -> 05H + 05H -> 0AH

#+begin_src shell :eval never
>>> STA 3322H
#+end_src
#+begin_src shell :exports results :results output
echo "STA 3322H" | python main.py -i -db /tmp/pyassm-readme-01
#+end_src

#+RESULTS:
: 3322H -> 0AH

#+begin_src shell :eval never
>>> inspect
#+end_src
#+begin_src shell :exports results :results output
echo "inspect" | python main.py -i -db /tmp/pyassm-readme-01
#+end_src

#+RESULTS:
#+begin_example
Registers:
A: 0x0a
B: 0x05
C: 0x05
D: 0x00
E: 0x00
H: 0x00
L: 0x00
M: 0x00

Memory:
0x1000: 0x2b
0x1001: 0x34
0x0000: 0x00
0x3322: 0x0a

Flags:
carry: 0
auxillary_carry: 0
zero: 0
sign: 0
#+end_example

** Example Command line Workflow
*** The file option (=-f=)
#+begin_src shell :exports both :results output
echo "MVI B 05H" > test.txt
echo "MVI A 00H" >> test.txt
python main.py -f test.txt
#+end_src

#+RESULTS:
: B -> 05H
: A -> 00H

#+begin_src shell :exports none :results none
# clean up
rm -f test.txt
#+end_src

*** The command option (=-c=)
#+begin_src shell :exports both :results output
python main.py -c "MVI B 05H"
#+end_src

#+RESULTS:
: B -> 05H

#+begin_src shell :exports both :results output
python main.py -c "MVI A 00H; MVI B 05H; ADD B"
#+end_src

#+RESULTS:
: A -> 00H
: B -> 05H
: A -> 00H + 05H -> 05H

*** The json file db option (=-db=)
Specifying the file db option saves the state of interpreter to a json file and restores from it every time a *8085 command* is executed.

This is useful when trying to run multiple =-c= commans as a session.
#+begin_src shell :exports both :results output
python main.py -db /tmp/pyassm-readme-02 -c "MVI B 05H"
#+end_src

#+RESULTS:
: B -> 05H

#+begin_src shell :exports both :results output
python main.py -db /tmp/pyassm-readme-02 -c "MVI A 00H; ADD B"
#+end_src

#+RESULTS:
: A -> 00H
: A -> 00H + 05H -> 05H

#+begin_src shell :exports both :results output
python main.py -db /tmp/pyassm-readme-02 -c "STA 5555H; inspect"
#+end_src

#+RESULTS:
#+begin_example
5555H -> 05H
Registers:
A: 0x05
B: 0x05
C: 0x00
D: 0x00
E: 0x00
H: 0x00
L: 0x00
M: 0x00

Memory:
0x1000: 0x2b
0x1001: 0x34
0x0000: 0x00
0x5555: 0x05

Flags:
carry: 0
auxillary_carry: 0
zero: 0
sign: 0
#+end_example

*** The plain/indirect mode option (=-i=)
This is very useful for piping interactions to and from other applications.
It is also recommended to run in =-db= file mode for continuous session-like interaction.
#+begin_src shell :exports both :results output
echo "MVI B 05H" | python main.py -i
#+end_src

#+RESULTS:
: B -> 05H

#+begin_src shell :exports both :results output
echo "MVI B 05H\nADD B" | python main.py -i
#+end_src

#+RESULTS:
: B -> 05H
: A -> 00H + 05H -> 05H

*** The verbosity logging option (=-v=)
You can customize the verbosity of logging messages by providing,
- =d= : For =DEBUG= level
- =e= : For =ERROR= level
- =w= : For =WARNING= level
- =i= : For =INFO= level

#+begin_src shell
echo "MVI B 05H" | python main.py -i -v d
#+end_src

#+RESULTS:
: B -> 05H

** Using From Terminal, Vim and Emacs
The command line options provided by interpreter allows it to be used through editors like Vim and Emacs.
Either you can:
- Use the =-f= option and write and execute using a temp buffer/file.
- Use combination of =-c= and =-db= option to emulate a repl session.
- Use combnation of =-i= and =-db= option to emulate a repl session.

*** Example Emacs Org babel config
With some configuration, the interpreter can be made to work with Emacs' Org Mode using the =org-babel-eval= function.
This uses =-i= command option to write to the interpreter.

Put this in your =init.el= file,
#+begin_src emacs-lisp :eval never
(defcustom path-to-8085 "~/dev/8085-interpreter/"
"Path to folder where 8085-interpreter was cloned")

(defcustom org-babel-8085-command
(concat
"python"
(concat path-to-8085 "/main.py"))
"Name of the command for executing 8085 interpreter.")

(defun org-babel-execute:8085 (body params)
(let ((args (cdr (assoc :args params))))
(org-babel-eval
(concat
org-babel-8085-command
(if args (concat " -i " args) " -i " ))
body)))

;; Placeholder major mode, look below for more featured major mode
(define-derived-mode 8085-mode prog-mode "8085"
"Major mode for 8085."
(setq-local comment-start ";")
(setq-local comment-start-skip ";+[\t ]*"))
#+end_src

- The =path-to-8085= should be folder where you cloned this project.
- The =org-babel-8085-command= should be the command to run the interpreter (eg python main.py),
- You could use =(concat path-to-8085 "/.venv/bin/python")= in place of "=python=" if you use in-project virtual environments.

*** Emacs 8085 major mode
#+begin_src emacs-lisp :eval never
(require 'rx)
(defvar 8085-mode-map
(let ((map (make-sparse-keymap)))
map))

(defconst 8085--font-lock-defaults
(let (
(instructions '("MVI" "MOV" "ADD" "SUB" "ADI"
"SUI" "JNZ" "JNC" "JZ" "JC" "LXI"
"LXAD" "INR" "DCR" "INX" "DCX" "OUT"
"HLT" "CPI" "CMP" "STA" "LDA")))
`(((,(rx-to-string `(: (or ,@instructions))) 0 font-lock-keyword-face)
("\\([[:word:]]+\\):" 1 font-lock-function-name-face)))))

(defvar 8085-mode-syntax-table
(let ((st (make-syntax-table)))
;; - and _ are word constituents
(modify-syntax-entry ?_ "w" st)
(modify-syntax-entry ?- "w" st)

;; add comments. lua-mode does something similar, so it shouldn't
;; bee *too* wrong.
(modify-syntax-entry ?\; "<" st)
(modify-syntax-entry ?\n ">" st)
st))

(define-derived-mode 8085-mode prog-mode "8085"
"Major mode for 8085."
(setq font-lock-defaults 8085--font-lock-defaults)
(setq-local comment-start ";")
(setq-local comment-start-skip ";+[\t ]*")
(setq-local case-fold-search nil))
#+end_src

Save and restart your emacs (or execute each block with =C-x C-e=).
Then you can use org mode to write block like:

- Use =C-c C-c= to execute a given block.
#+begin_example
,#+begin_src 8085 :args -v d -db /tmp/8085-session1
MVI B 80H
,#+end_src
#+end_example

- For session-like use,
#+begin_example
,#+begin_src 8085 :args -v d -db /tmp/8085-session1
MVI B 80H
,#+end_src
#+end_example

- For verbose logging,
#+begin_example
,#+begin_src 8085 :args -v d -db /tmp/8085-session1
MVI B 80H
,#+end_src
#+end_example

** [[file:usage_examples.org][Extensive Usage Examples]]