MFD-0816 TECHNICAL SPECIFACTION & OVERVIEW November 2024 CONTENTS ──────────────────────────────────────────────────────────────────────────────── 1..... INTRODUCTION & OVERVIEW 1.1... PINS 2..... REGISTERS 2.1... GENERAL PURPOSE REGISTERS 2.2... SPECIALIZED REGISTERS 2.2.1. THE STACK 2.2.2. FLAGS 3..... ADDRESSING & THE I/O BUS 3.1... I/O BUS INSTRUCTIONS 4..... INSTRUCTION SET OVERVIEW 4.1... INSTRUCTION ENCODING 4.1.1. REGISTER IDENTIFICATION 5..... ADDRESSING MODES 6..... INTERRUPTS 6.1... HARDWARE INTERRUPTS 6.2... SOFTWARE INTERRUPTS 7..... RESET ...... LICENSE 1. INTRODUCTION & OVERVIEW ──────────────────────────────────────────────────────────────────────────────── The MFD-0816 is a 16-bit fantasy CPU and based on the intel 8088. ► 16-bit address bus ► 16-bit word ► 8-bit I/O bus ► 4x 16-bit general purpose register 1.1. PINS ──────────────────────────────────────────────────────────────────────────────── ┌───────┬────────┬────────────────────────────────────────────────┐ │ NAME │ PINS │ DESCRIPTION │ ├───────┼────────┼────────────────────────────────────────────────┤ │ CLK │ 00 │ Clock pin. When high the CPU executes one step │ ├───────┼────────┼────────────────────────────────────────────────┤ │ AIO │ 01..16 │ 16-bit Memory IO Bus │ ├───────┼────────┼────────────────────────────────────────────────┤ │ GIO │ 17..24 │ 8-bit IO Bus │ ├───────┼────────┼────────────────────────────────────────────────┤ │ IRQ │ 25 │ Interrupt Request │ ├───────┼────────┼────────────────────────────────────────────────┤ │ IRA │ 26 │ Interrupt Acknowledge │ ├───────┼────────┼────────────────────────────────────────────────┤ │ RESET │ 27 │ Reset │ ├───────┼────────┼────────────────────────────────────────────────┤ │ AMS │ 28 │ Memory IO Bus Mode Select │ ├───────┼────────┼────────────────────────────────────────────────┤ │ GMS │ 29 │ 8-bit IO Bus Mode Select │ └───────┴────────┴────────────────────────────────────────────────┘ 2. REGISTERS 2.1. GENERAL PURPOSE REGISTERS ──────────────────────────────────────────────────────────────────────────────── The MFD-0816 has 4 16-bit general purpose registers with the following names: ► ACL (AH & AL) ► BCL (BH & BL) ► CCL (CH & CL) ► DCL (DH & DL) Each general purpose register of the MFD-0816 is usable as either a complete WORD or as its high and low bytes. ┌─────────┐ │ ACL │ ├────┬────┤ │ AH │ AL │ └────┴────┘ The above illustration shows the register "ACL", which can be used as a complete word with this name, alternatively its high byte can be accessed with the "AH" name and the low byte using "AL". 2.2. SPECIALIZED REGISTERS ──────────────────────────────────────────────────────────────────────────────── The MFD-0816 has the following specialized registers: ► SP (Stack Pointer) ► IP (Instruction Pointer) ► AR (Accumulator) ► FL (Flags) ► IID (Interrupt ID) All of these registers have a size of one word. The Stack Pointer register holds the current address of the top of the stack. The Instruction Pointer register holds the address of the current instruction. The Accumulator register holds the result of the last arithmetic operation The Flags register holds an assortment of different bit flags, elaborated upon in chapter 2.2.2. Bits can only be set by their respective clear and set instructions. The IID register hold the value of the last interrupt. It can only be set via an interrupt. 2.2.1. THE STACK ──────────────────────────────────────────────────────────────────────────────── The stack is a memory structure where the first element "pushed" on to it will be the last element to leave it. In the case of the MFD-0816, one stack-element is a word. In the case of this CPU, the stack grows "downwards" (the address of the top of the stack gets smaller the larger it gets). This address is held in the SP register. In case the value of SP is equal to 0 and another element is "pushed" onto the stack it will cause a CPU exception to be thrown. The starting location of the stack is not fixed and must be set when initializing the CPU. This is simply done by loading the SP register with the address where the stack should start. Note that this address must always be a multiple of two. 2.2.2. FLAGS ──────────────────────────────────────────────────────────────────────────────── ┌──────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ BIT │ 0F │ 0E │ 0D │ 0C │ 0B │ 0A │ 09 │ 08 │ 07 │ 06 │ 05 │ 04 │ 03 │ ├──────┼────┼────┼────┼────┼────┼────┼────┼────┼────┼────┼────┼────┼────┤ │ NAME │ OF │ CF │ ZF │ NF │ IE │ RT │ RS │ RS │ RS │ RS │ RS │ RS │ RS │ └──────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ ┌──────┬────┬────┬────┐ │ BIT │ 02 │ 01 │ 00 │ ├──────┼────┼────┼────┤ │ NAME │ RS │ RS │ RS │ └──────┴────┴────┴────┘ ► OF (Overflow Flag) Set if the last arithmetic operation overflowed. ► CF (Carry Flag) Set to indicate that an arithmetic carry has been generated. ► ZF (Zero Flag) Set to indicate that the last arithmetic operation resulted in a value equal to 0 in the accumulator register. ► NF (Negative Flag) Set if the result of the last arithmetic operation has its highest (left most) bit set. ► IE (Interrupt Enable) If set, interrupts are enabled and will be handled. ► RT (Reset) If set, the processor is in the reset process. ► RS (Reserved) Bits marked with this name are reserved for future use. 3. ADDRESSING & THE I/O BUS ──────────────────────────────────────────────────────────────────────────────── The MFD-0816 provides a regular address & data bus mainly used for loading of instructions and memory. The address bus and its corresponding data bus are both 16-bits wide. The high-byte of the received data may be ignored by the CPU if not needed. Write Operation: T1 ╷ T2 ╷ CLK ┌──────────────────┐ ┌────────────────────┐ ──┘ └────────────────────┘ └─ AMS ┌────────────────────┐ ┘ └─────────────────────────────────────────── 🮣───────────────────🮢 🮣────────────────────🮢 AIO ─🮤 ADDRESS OUT 🮥────────────────────🮤 DATA OUT 🮥─ 🮡───────────────────🮠 🮡────────────────────🮠 Read Operation: T1 ╷ T2 ╷ CLK ┌──────────────────┐ ┌────────────────────┐ ──┘ └──────────────────┘ └─ AMS ┌────────────────────────────────────────────────────────────┐ ┘ └─ 🮣───────────────────🮢 🮣────────────────────🮢 AIO ─🮤 ADDRESS OUT 🮥──────────────────🮤 DATA IN 🮥─ 🮡───────────────────🮠 🮡────────────────────🮠 ► If AMS is high during T1, the operation is a write opeartion. If AMS is also hgih during T2, it is a read operation. ► During T1 the 16-bit address is set. ► (Write Operation) During T2 the word to be written is set in case of a write operation. ► (Write Operation) During T2 the requested data must be set by the peer. An 8-bit I/O bus is also provided for interacting with external hardware without requiring memory-mapping. Write Operation: T1 ╷ T2 ╷ T3 ╷ T4 ╷ CLK ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ─┘ └──────┘ └──────┘ └──────┘ └─ GMS ┌─────────────────────┐ ┘ └───────────────────────────── 🮣────────────────────🮢 🮣────────────────────🮢 GIO ─🮤 ADDRESS OUT 🮥──────🮤 DATA OUT 🮥─ 🮡────────────────────🮠 🮡────────────────────🮠 Read Operation: T1 ╷ T2 ╷ T3 ╷ T4 ╷ CLK ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ─┘ └──────┘ └──────┘ └──────┘ └─ GMS ──────────────────────────────────────────────────── 🮣────────────────────🮢 🮣────────────────────🮢 GIO ─🮤 ADDRESS OUT 🮥──────🮤 DATA IN 🮥─ 🮡────────────────────🮠 🮡────────────────────🮠 ► If GMS is high only during T1, the operation is a write opeartion. If it is also high during T2, it is a read operation. ► During T1 the high-byte of the 16-bit address is set. ► During T2 the low-byte of the 16-bit address is set. ► (Write Operation) During T3 the high-byte of the word is set. ► (Write Operation) During T4 the low-byte of the word is set. ► (Read Operation) During T3 the high-byte of the word must be set by the peer. ► (Read Operation) During T4 the low-byte of the word must be set by the peer. 3.1. I/O BUS INSTRUCTIONS ──────────────────────────────────────────────────────────────────────────────── Four instructions for operation on the I/O BUS are provided: ► OUT - Write data to the bus ► IN - Read data from the bus ► BOT - Write a block of data to the bus ► BIN - Read a block of data from the bus 4. INSTRUCTION SET OVERVIEW ──────────────────────────────────────────────────────────────────────────────── ┌──────┬──────────────────────────────────┬────────────┐ │ NAME │ MEANING │ OPCODE(S) │ ├──────┼──────────────────────────────────┼────────────┤ │ ADC │ Add with carry │ 0x00 │ ├──────┼──────────────────────────────────┼────────────┤ │ ADD │ Add │ 0x01 │ ├──────┼──────────────────────────────────┼────────────┤ │ AND │ Logical AND │ 0x02 │ ├──────┼──────────────────────────────────┼────────────┤ │ BIN │ Read block of data from I/O │ 0x03 │ ├──────┼──────────────────────────────────┼────────────┤ │ BOT │ Write block of data to I/O │ 0x04 │ ├──────┼──────────────────────────────────┼────────────┤ │ CALL │ Call subroutine │ 0x05 │ ├──────┼──────────────────────────────────┼────────────┤ │ CLf │ Clear flag │ 0x2b..0x3a │ ├──────┼──────────────────────────────────┼────────────┤ │ CMP │ Compare operands │ 0x07 │ ├──────┼──────────────────────────────────┼────────────┤ │ DEC │ Decrement by 1 │ 0x08 │ ├──────┼──────────────────────────────────┼────────────┤ │ DIV │ Unsigned divide │ 0x09 │ ├──────┼──────────────────────────────────┼────────────┤ │ IDIV │ Signed divide │ 0x0a │ ├──────┼──────────────────────────────────┼────────────┤ │ IMUL │ Signed multiply │ 0x0b │ ├──────┼──────────────────────────────────┼────────────┤ │ IN │ Read data from I/O │ 0x0c │ ├──────┼──────────────────────────────────┼────────────┤ │ INC │ Increment by 1 │ 0x0d │ ├──────┼──────────────────────────────────┼────────────┤ │ INT │ Trigger interrupt │ 0x0e │ ├──────┼──────────────────────────────────┼────────────┤ │ IRET │ Return from interrupt │ 0x0f │ ├──────┼──────────────────────────────────┼────────────┤ │ Jcc │ Jump (if condition) │ 0x10..0x1a │ ├──────┼──────────────────────────────────┼────────────┤ │ LD │ Load word to register │ 0x1b │ ├──────┼──────────────────────────────────┼────────────┤ │ MOV │ Mov value between registers │ 0x1c │ ├──────┼──────────────────────────────────┼────────────┤ │ MUL │ Unsigned multiply │ 0x1d │ ├──────┼──────────────────────────────────┼────────────┤ │ NEG │ Negate │ 0x1e │ ├──────┼──────────────────────────────────┼────────────┤ │ NOP │ No operation │ 0x1f │ ├──────┼──────────────────────────────────┼────────────┤ │ NOT │ Negate the operand (logical NOT) │ 0x20 │ ├──────┼──────────────────────────────────┼────────────┤ │ OR │ Logical OR │ 0x21 │ ├──────┼──────────────────────────────────┼────────────┤ │ OUT │ Write data to I/O │ 0x22 │ ├──────┼──────────────────────────────────┼────────────┤ │ POP │ Pop data from stack │ 0x23 │ ├──────┼──────────────────────────────────┼────────────┤ │ PUSH │ Push data onto stack │ 0x24 │ ├──────┼──────────────────────────────────┼────────────┤ │ RET │ Return from subroutine │ 0x25 │ ├──────┼──────────────────────────────────┼────────────┤ │ ROL │ Rotate left │ 0x26 │ ├──────┼──────────────────────────────────┼────────────┤ │ ROR │ Roate right │ 0x27 │ ├──────┼──────────────────────────────────┼────────────┤ │ SL │ Shift left │ 0x28 │ ├──────┼──────────────────────────────────┼────────────┤ │ SR │ Shift right │ 0x29 │ ├──────┼──────────────────────────────────┼────────────┤ │ ST │ Store word from register │ 0x2a │ ├──────┼──────────────────────────────────┼────────────┤ │ STf │ Set flag │ 0x3b..0x4a │ ├──────┼──────────────────────────────────┼────────────┤ │ SUB │ Subtraction │ 0x4b │ ├──────┼──────────────────────────────────┼────────────┤ │ TEST │ Logical compare (AND) │ 0x4c │ ├──────┼──────────────────────────────────┼────────────┤ │ XOR │ Exclusive OR │ 0x4d │ └──────┴──────────────────────────────────┴────────────┘ 4.1 INSTRUCTION ENCODING ──────────────────────────────────────────────────────────────────────────────── ┌────────┬────────┬───────────────────────────────────────────┐ │ WORD │ BITS │ USAGE │ ├────────┼────────┼───────────────────────────────────────────┤ │ 00 │ 0F..08 │ Identification of the instruction │ ├────────┼────────┼───────────────────────────────────────────┤ │ 00 │ 07..04 │ Operand 1 addressing mode │ ├────────┼────────┼───────────────────────────────────────────┤ │ 00 │ 03..00 │ Operand 2 addressing mode │ └────────┴────────┴───────────────────────────────────────────┘ The addressing modes are encoded as follows: ┌────────┬────────────────────────────┐ │ VALUE │ MODE │ ├────────┼────────────────────────────┤ │ 0000 │ Immediate │ ├────────┼────────────────────────────┤ │ 0001 │ Direct │ ├────────┼────────────────────────────┤ │ 0010 │ Indirect │ ├────────┼────────────────────────────┤ │ 0101 │ Relative Direct │ ├────────┼────────────────────────────┤ │ 0110 │ Relative Indirect │ ├────────┼────────────────────────────┤ │ 1000 │ Register Immediate │ ├────────┼────────────────────────────┤ │ 1001 │ Register Direct │ ├────────┼────────────────────────────┤ │ 1010 │ Register Indirect │ ├────────┼────────────────────────────┤ │ 1101 │ Register Relative Direct │ ├────────┼────────────────────────────┤ │ 1110 │ Register Relative Indirect │ └────────┴────────────────────────────┘ The highest bit (bit 03) is reffered to as the register bit. If high, the operand's immediate value identifies a register. The second highest bit (bit 02) is the relative bit. If high, the operands value is relative to the value of the IP register. The second lowest bit (bit 01) is the indirect bit. If high, the value behind the operand is another address which must be read from. The lowest bit (bit 00) is the direct bit. If high, the operand is an address pointing towards the actual value to be worked with. Bits 00 and 01 should not be set at the same time. Should the CPU encounter this, an exception will be raised. Bit 02 has no effect if neither Bit 01 or Bit 00 are high. 4.1.1. REGISTER IDENTIFICATION ──────────────────────────────────────────────────────────────────────────────── In case the register bit is set for a specific operand, the immediate value is only one byte long. The register is encoded as follows: ┌─────┬───────┐ │ REG │ VALUE │ ├─────┼───────┤ │ AL │ 0x00 │ ├─────┼───────┤ │ AH │ 0x01 │ ├─────┼───────┤ │ ACL │ 0x02 │ ├─────┼───────┤ │ BL │ 0x03 │ ├─────┼───────┤ │ BH │ 0x04 │ ├─────┼───────┤ │ BCL │ 0x05 │ ├─────┼───────┤ │ CL │ 0x06 │ ├─────┼───────┤ │ CH │ 0x07 │ ├─────┼───────┤ │ CCL │ 0x08 │ ├─────┼───────┤ │ DL │ 0x09 │ ├─────┼───────┤ │ DH │ 0x0a │ ├─────┼───────┤ │ DCL │ 0x0b │ ├─────┼───────┤ │ SP │ 0x0c │ ├─────┼───────┤ │ IP │ 0x0d │ ├─────┼───────┤ │ AR │ 0x0e │ ├─────┼───────┤ │ FL │ 0x0f │ ├─────┼───────┤ │ IID │ 0x10 │ └─────┴───────┘ 5. ADDRESSING MODES ──────────────────────────────────────────────────────────────────────────────── Addressing modes define how instructions access operands. There are three primary modes: Immediate, Direct, and Indirect. In Immediate Addressing, the operand is either a literal value or a register value. For example, in the instruction "MOV #64, AL", the immediate value 64 is assigned directly to the register AL, making AL equal to 64. ┌─────────────┬─────────┐ │ INSTRUCTION │ OPERAND │ └─────────────┴─────────┘ IMMEDIATE ADDRESSING In Direct Addressing, the operand specifies an address where the actual value is stored. The instruction accesses the value directly from this address. ┌─────────────┬───────────────────┐ ┌───────┐ │ INSTRUCTION │ OPERAND (ADDRESS) ├────────►│ VALUE │ └─────────────┴───────────────────┘ └───────┘ DIRECT ADDRESSING Indirect Addressing also uses an address as the operand, but instead of pointing directly to the value, the address points to another address where the final value is stored. This requires an extra level of indirection. ┌─────────────┬───────────────────┐ ┌────────────────────────────┐ │ INSTRUCTION │ OPERAND (ADDRESS) ├────────►│ POINTER TO VALUE (ADDRESS) ├─┐ └─────────────┴───────────────────┘ ├────────────────────────────┤ │ INDIRECT ADDRESSING │ VALUE │◄┘ └────────────────────────────┘ Direct and Indirect modes typically use absolute addresses. However, they can also operate in Relative Addressing mode, where the address is calculated relative to the current value of the Instruction Pointer (IP) register. ► To reference a memory location before the current IP value, the highest bit of the address must be set, indicating a negative offset. 6. INTERRUPTS ──────────────────────────────────────────────────────────────────────────────── Interrupts can be triggered by the INT instruction or the INT-Pin being pulled high. Both types of interrupts share this behaviour after acquiring the interrupt id. 1. Save the value of the IP register to the top of the stack 2. Load the value from the interrupt vector into the IP register. The interrupt vector is located at address 0xfffc 3. Clear the IE flag 4. Continue execution After handling of an interrupt is done, the IRET instruction must be invoked. This does the following: 1. Set the IE flag 2. Load the value from the top of the stack into the IP register 3. continue execution 6.1. HARDWARE INTERRUPTS ──────────────────────────────────────────────────────────────────────────────── Hardware interrupts consist of two sequences: The Interrupt request and the Interrupt Acknowledge sequence. Interrupt request: T1 ╷ CLK ┐ ┌──────┐ ┌ └──────┘ └──────┘ IRQ ┌──────┐ ───────┘ └─────── The CPU checks if the IRQ line is high at the ench of each clock cycle. So if IRQ is high at the end of T1, an interrupt was requested. After this sequence, the Acknowledge sequence is entered. Interrupt acknowledge: T1 ╷ T2 ╷ CLK ┐ ┌─────────┐ ┌─────────┐ └─────────┘ └─────────┘ └─ IRA ┌─────────────────────────────┐ ──────────┘ └─ 🮣──────────🮢 GIO ─────────────────────────────🮤 DATA IN 🮥─ 🮡──────────🮠 As soon as the CPU is ready, it will set the IRA line high for two clock pulses. During the first pulse, nothing else happens. During the second pulse the CPU reads a byte of whatever data currently is on the I/O Bus. This data is used as the interrupt id and written to the IID register. After both sequences are completed, the CPU continues with the shared behaviour specified in chapter 6. 6.1. SOFTWARE INTERRUPTS ──────────────────────────────────────────────────────────────────────────────── Software interrupts are a lot simpler. They are triggered by an INT instruction. When an INT instruction is encountered, the CPU first sets the IID register to the value of the first operand of the instruction. After this is completed, the CPU continues with the shared behaviour specified in chapter 6. 7. RESET ──────────────────────────────────────────────────────────────────────────────── The CPU can be reset to start execution from the reset vector. The reset vector is located at address 0xfffe. T1 ╷ T2 ╷ T3 ╷ CLK ┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ └─────────┘ └─────────┘ └─────────┘ └ RESET ┌─────────┐ ──────────┘ └──────────────────────────────────────── In order to execute a reset, the RESET pin must be high at the end of a clock pulse. If reset is high for longer than this, it will continually reset the processor. After a reset has been triggered, the RT flag is set and the next few cycles are used to read the value of the reset vector into the IP register. Afterwards, the RT flag is cleared and the processor resumes execution. Note that resetting does not clear any registers or memories except for the FL register. Interrupts also have no effect whilst resetting, regardless of the state of the IE flag. LICENSE ──────────────────────────────────────────────────────────────────────────────── MFD0816 DESIGN by Marie Eckert is licensed under CC BY-SA 4.0, see