website/data/projects/mfd0816/VERSION1_DESIGN

569 lines
38 KiB
Plaintext
Raw Normal View History

2024-12-04 19:52:05 +01:00
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 <https://creativecommons.org/licenses/by-sa/4.0/>