ocreMutiny -- a tiny OCR assembly language emulator
ocreMutiny is a simple emulator, that implements the following assembler instruction set, with input error checking. The emulator is 1021 bytes of crushed JavaScript, which can be seen in the HTML source of this page.
To use it, type in the assembly code in the textarea. Click "Load" to load in the code into memory. Then click "Step" to run the code line by line. If errors were found it will tell you which line, otherwise the line number of the line that is about to be executed is displayed. Q is the output port, and A0 to A7 show the current contents of the registers.
The emulator understands the instructions shown in the table below. It is case insensitive. Byte literals are in hexadecimal, in the format $xx
. Also supported are line comments (delimited by ;
).
Assembler | Function |
---|---|
MOVI Ad, n | Copy the byte n into register Ad |
MOV Ad, As | Copy the byte from As to Ad |
ADD Ad, As | Add the byte in As to the byte in Ad and store the result in Ad |
SUB Ad, As | Subtract the byte in As from the byte in Ad and store the result in Ad |
AND Ad, As | Logical AND the byte in As with the byte in Ad and store the result in Ad |
EOR Ad, As | Logical EOR the byte in As with the byte in Ad and store the result in Ad |
INC Ad | Add 1 to Ad |
DEC Ad | Subtract 1 from Ad |
IN Ad, I | Copy the byte at the input port into Ad |
OUT Q, As | Copy the byte in As to the output port |
JP e | Jump to label e |
JZ e | Jump to label e if the result of the last ADD, SUB, AND, EOR, INC, DEC, SHL or SHR was zero |
JNZ e | Jump to label e if the result of the last ADD, SUB, AND, EOR, INC, DEC SHL or SHR was not zero |
RCALL s | Push the program counter onto the stack to store the return address and then jump to label s |
RET | Pop the program counter from the stack to return to the place the subroutine was called from |
SHL Ad | Shift the byte in Ad one bit left putting a 0 into the lsb |
SHR Ad | Shift the byte in Ad one bit right putting a 0 into the msb |
Example:
movi a0, $ff out q, a0 in a0, i rcall loop end: out q, a0 jp end loop: dec a0 jz done rcall loop done: ret
Originally the code had two parts to it -- a bytecode assembler that would parse the input and generate a simple bytecode format, and an interpreter that would consume the bytecode. However in the interests of space I merged these two together. Lexing is still done in one go on load using a regex. However, some error checking is now deferred until the line which contains the error is executed.
The hand-minified code before crushing is shown below: