From 0fd6413d81464c89c69468cbdb8ec14eb459678f Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Sat, 17 Jun 2023 16:56:42 -0500 Subject: [PATCH] Updated the instruction set and mapped out the opcodes as well as wrote a sample program to see if the ISA was complete enough to build a trivial program. --- docs/document.tex | 129 +++++++++++++++++++++--------------------- misc/another_test.asm | 43 +++++++++++++- 2 files changed, 106 insertions(+), 66 deletions(-) diff --git a/docs/document.tex b/docs/document.tex index b89e431..fc241c5 100644 --- a/docs/document.tex +++ b/docs/document.tex @@ -8,12 +8,12 @@ \title{Unnamed Machine} \author{A Very Terrible 16-bit Machine} -\newcommand{\OpcodeTable}[4] { - \begin{tabular}{ c c c c } +\newcommand{\OpcodeTable}[5] { + \begin{tabular}{ c c c c c } \hline - Opcode & Mnemonic & Operand 1 & Operand 2 \\ + Opcode & Bit Pattern & Mnemonic & Operand 1 & Operand 2 \\ \hline\hline - #1 & #2 & #3 & #4 \\ + #1 & #2 & #3 & #4 & #5 \\ \hline \end{tabular} } @@ -91,91 +91,94 @@ "store" and "load" and have the assembler pick the opcode based on the inclusion of the word "byte" or "word" for two bytes. That would make the assembly easier to read but put a bit more work on the assembler. The Stack Pointer will start 2 bytes above the video memory start. - \section{STOB (Store Byte)} - \OpcodeTable{0x20}{stob}{Register}{Register}\\[6pt] - Stores a single byte (the lower nibble) from a register to a memory address store in a register. - \section{STOW (Store Machine Word)} - \OpcodeTable{0x20}{stow}{Register}{Register}\\[6pt] - Stores a machine word from a register to a memory address stored in a register. - \section{LAA (Load Absolute Address)} - \OpcodeTable{0x00}{laa}{Register}{Address}\\[6pt] - Loads an address (2 bytes) into the register. - \section{LODB (Load Byte)} - \OpcodeTable{0x20}{lodb}{Register}{Register}\\[6pt] - Loads a single byte into a register from a memory address in the second operand register, zeroing out the high nibble. - \section{LODW (Load Machine Word)} - \OpcodeTable{0x20}{lodw}{Register}{Register}\\[6pt] - Loads a word into a register from a memory address in the second operand register. - \section{LODWI (Load Immediate Word)} - \OpcodeTable{0x00}{lodwi}{Register}{Constant}\\[6pt] - Loads an immediate machine word into the register clearing the high nibble if the value is less then 256. + \section{COPY (Copy Word from Address)} + \OpcodeTable{0x08}{0000 1000}{copy}{Register}{Address}\\[6pt] + Copy a machine word from Operand 2 into Operand 1. + \section{COPY BYTE (Copy Byte from Address)} + \OpcodeTable{0x10}{0001 0000}{copy byte}{Register}{Address}\\[6pt] + Copy a byte (8 bits) from Operand 2 into Operand 1, clearing the setting the most significant bits to zero. + \section{COPY (Copy Word Indirect Address)} + \OpcodeTable{0x18}{0001 1000}{copy}{Register}{[Register]}\\[6pt] + Copy a machine word from the address stored in Operand 2 into Operand 1. + \section{COPY BYTE (Copy Byte Indirect Address)} + \OpcodeTable{0x20}{0010 0000}{copy byte}{Register}{[Register]}\\[6pt] + Copy a byte (8 bits) from the address stored in Operand 2 into Operand 1. + \section{COPY (Copy)} + \OpcodeTable{0x28}{0010 1000}{copy}{[Register]}{[Register]}\\[6pt] + Copy a machine word from the address stored in Operand 2 into the address stored in Operand 1. + \section{COPY BYTE (Copy Byte)} + \OpcodeTable{0x30}{0011 0000}{copy byte}{[Register]}{[Register]}\\[6pt] + Copy a byte (8 bits) from the address stored in Operand 2 into the address stored in Operand 1. + \section{COPY (Copy)} + \OpcodeTable{0x38}{0011 1000}{copy}{Register}{Register}\\[6pt] + Copy a machine word from Operand 2 into Operand 1. + \section{COPY BYTE (Copy Byte)} + \OpcodeTable{0x40}{0100 0000}{copy byte}{Register}{Constant}\\[6pt] + Copy a byte (8 bits) from Operand 2 into Operand 1. \section{CMP (Compare)} - \OpcodeTable{0x20}{cmp}{Register}{Register}\\[6pt] + \OpcodeTable{0x48}{0100 1000}{cmp}{Register}{Register}\\[6pt] Compares two registers and somewhere sets a result in the status register. \section{CMPI (Compare Immediate)} - \OpcodeTable{0x00}{cmpi}{Register}{Constant}\\[6pt] + \OpcodeTable{0x50}{0101 0000}{cmpi}{Register}{Constant}\\[6pt] Compares an immediate 2 byte value to the contents of a register setting the status register accordingly. \section{ADD (Add)} - \OpcodeTable{0x20}{add}{Register}{Register}\\[6pt] + \OpcodeTable{0x58}{0101 1000}{add}{Register}{Register}\\[6pt] Performs addition on a register with a value from another (or the same) register. \section{SUB (Subtract)} - \OpcodeTable{0x20}{sub}{Register}{Register}\\[6pt] + \OpcodeTable{0x60}{0110 0000}{sub}{Register}{Register}\\[6pt] Performs subtraction on a register with a value from another (or the same) register. - \section{JMP (Jump)} - \OpcodeTable{0x20}{jmp}{Register}{None}\\[6pt] - Jumps unconditionally to a memory address. Sets the Program Counter to Address. - \section{JZ (Jump if Zero)} - \OpcodeTable{0x20}{jz}{Register}{None}\\[6pt] - Jumps to a memory address if the status flag is zero. - \section{JG (Jump if Greater Than)} - \OpcodeTable{0x70}{jg}{Register}{None}\\[6pt] - Jump to the Address if the status flag is greater than zero. - \section{JL (Jump if Less Than)} - \OpcodeTable{0x00}{jl}{Register}{None}\\[6pt] - Jumps to the address if the status flag is less than zero. - \section{JMPA (Jump to Address)} - \OpcodeTable{0x20}{jmpa}{Address}{None}\\[6pt] - Jumps unconditionally to a memory address. Sets the Program Counter to Address. - \section{JZA (Jump to Address if Zero)} - \OpcodeTable{0x20}{jza}{Address}{None}\\[6pt] - Jumps to a memory address if the status flag is zero. - \section{JGA (Jump to Address if Greater Than)} - \OpcodeTable{0x70}{jga}{Address}{None}\\[6pt] - Jump to the Address if the status flag is greater than zero. - \section{JLA (Jump to Address if Less Than)} - \OpcodeTable{0x00}{jla}{Address}{None}\\[6pt] - Jumps to the address if the status flag is less than zero. \section{AND (Logical AND)} - \OpcodeTable{0x00}{and}{Register}{Register}\\[6pt] + \OpcodeTable{0x70}{0111 0000}{and}{Register}{Register}\\[6pt] Logical ANDs the two registers together storing the result in operand 1. \section{XOR (Logical Exclusive OR)} - \OpcodeTable{0x00}{xor}{Register}{Register}\\[6pt] + \OpcodeTable{0x78}{0111 1000}{xor}{Register}{Register}\\[6pt] Logical XORs the two registers together storing the result in operand 1. \section{OR (Logical OR)} - \OpcodeTable{0x00}{or}{Register}{Register}\\[6pt] + \OpcodeTable{0x80}{1000 0000}{or}{Register}{Register}\\[6pt] Logical ORs the two registers together storing the result in operand 1. \section{NOT (Logical Negation)} - \OpcodeTable{0x00}{not}{Register}{None}\\[6pt] + \OpcodeTable{0x88}{1000 1000}{not}{Register}{None}\\[6pt] Inverts the bits of the target register. \section{SHR (Shift Right)} - \OpcodeTable{0x00}{shr}{Register}{Constant}\\[6pt] + \OpcodeTable{0x90}{1001 0000}{shr}{Register}{Constant}\\[6pt] Bit-wise shifts the contents of the register right Constant number of times. \section{SHL (Shift Left)} - \OpcodeTable{0x00}{shl}{Register}{Constant}\\[6pt] + \OpcodeTable{0x98}{1001 1000}{shl}{Register}{Constant}\\[6pt] Bit-wise shifts the contents of the register left Constant number of times. \section{INC (Increment)} - \OpcodeTable{0x00}{inc}{Register}{None}\\[6pt] + \OpcodeTable{0xA0}{1010 0000}{inc}{Register}{None}\\[6pt] Increments the contents of the register by one. Over-flows will not be reported. \section{DEC (Decrement)} - \OpcodeTable{0x00}{dec}{Register}{None}\\[6pt] + \OpcodeTable{0xA8}{1010 1000}{dec}{Register}{None}\\[6pt] Decrements the contents of the register by one. Under-flows will not be reported. - \section{NOP (No Operation)} - \OpcodeTable{0x00}{nop}{None}{None}\\[6pt] - Skips a clock cycle, incrementing the program counter. \section{Push} - \OpcodeTable{0x00}{push}{Register}{None} + \OpcodeTable{0xB0}{1011 0000}{push}{Register}{None} Pushes the value of Register onto the stack, decrementing the Stack Pointer by 2. \section{Pop} - \OpcodeTable{0x00}{pop}{Register}{None} + \OpcodeTable{0xB8}{1011 1000}{pop}{Register}{None} Pops the top of the stack into Register, incrementing the Stack Pointer by 2. + \section{JMPI (Jump Indirect)} + \OpcodeTable{0xC0}{1100 0000}{jmpi}{Register}{None}\\[6pt] + Jumps unconditionally to a memory address stored in Operand 1. Sets the Program Counter to Operand 1. + \section{JMP (Jump)} + \OpcodeTable{0x02}{0000 0010}{jmp}{Address}{None}\\[6pt] + Jumps unconditionally to a memory address. Sets the Program Counter to Address. + \section{JZ (Jump if Zero)} + \OpcodeTable{0x03}{0000 0011}{jz}{Address}{None}\\[6pt] + Jumps to a memory address if the status flag is zero. Sets the Program Counter to Address. + \section{JG (Jump if Greater Than)} + \OpcodeTable{0x04}{0000 0100}{jg}{Address}{None}\\[6pt] + Jump to the Address if the status flag is greater than zero. Sets the Program Counter to Address. + \section{JL (Jump if Less Than)} + \OpcodeTable{0x05}{0000 0101}{jl}{Address}{None}\\[6pt] + Jumps to the address if the status flag is less than zero. Sets the Program Counter to Address. + \section{NOP (No Operation)} + \OpcodeTable{0x01}{0000 0001}{nop}{None}{None}\\[6pt] + Skips a clock cycle, incrementing the program counter. + \section{CALL (Call Subroutine)} + \OpcodeTable{0x06}{0000 0110}{call}{Address}{None}\\[6pt] + Pushes the base address to the stack and sets the Program Counter to Address. + \section{RET (Return from Subroutine)} + \OpcodeTable{0x07}{0000 0111}{ret}{None}{None}\\[6pt] + Pops the stack and sets the Program Counter to that value. \end{document} diff --git a/misc/another_test.asm b/misc/another_test.asm index 7ad2976..b6aa256 100644 --- a/misc/another_test.asm +++ b/misc/another_test.asm @@ -1,3 +1,40 @@ -some_stub: - pop r8 - jmp [r8] ;return to the calling code. \ No newline at end of file +.db MAX_MEM 0xFFFF +.db VIDEO_MEM 0xF37F +.db MAX_LENGTH MAX_MEM - MAX_LENGTH +.db MSG "Hello, World!", 0 + +_start: + copy r1, MSG ; Pointer into r1 + copy r8, VIDEO_MEM + call strlen + copy r1, MSG + cmp r2, 0 + je _end + cmp r2, MAX_LENGTH + jg _end +draw_loop: + copy byte [r8], [r1] + inc r1 + inc r8 + dec r2 + cmp r2, 0 + je _end + jmp draw_loop +_end: + jmp _end + +; Returns the length of a NULL terminated string +; Arguments: R1 - Pointer to the string +; Returns: R2 - Contains the length of the string +strlen: + copy r2, 0 ; length + cmp [r1], 0 + je end ;The string is zero length +loop: + inc r1 + cmp [r1], 0 + je end + inc r2 + jmp loop +end: + ret \ No newline at end of file