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.
This commit is contained in:
+66
-63
@@ -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}
|
||||
|
||||
+40
-3
@@ -1,3 +1,40 @@
|
||||
some_stub:
|
||||
pop r8
|
||||
jmp [r8] ;return to the calling code.
|
||||
.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
|
||||
Reference in New Issue
Block a user