diff --git a/build.mb b/build.mb
index 13369ef..13bc53f 100644
--- a/build.mb
+++ b/build.mb
@@ -9,13 +9,18 @@ end
sector targets
section static
- list str c_rules 'sites'
+ list str c_rules 'sites', 'symlinks'
end
end
sector c_rules
section sites
- list str input 'index', 'projects/fpc-sitegen', 'projects/sad', 'projects/mariebuild'
+ list str input
+ 'index',
+ 'projects/fpc-sitegen',
+ 'projects/sad',
+ 'projects/mariebuild',
+ 'projects/mfd0816/index'
str input_format 'data/$(%element%).sad'
str output_format '$(%element%).html'
@@ -36,6 +41,23 @@ sed -i ''s/\\\$\\\$TIME\\\$\\\$/''"\$TIME/g" $(%output%)
sed -i ''s@\\\$\\\$BRANCH\\\$\\\$@''"\$BRANCH@g" $(%output%)
sed -i ''s@\\\$\\\$SOURCE\\\$\\\$@$(%input%)@g'' $(%output%)
sed -i ''s/\\\$\\\$COMMIT\\\$\\\$/''"\$COMMIT_SHORT/g" $(%output%)
+'
+ end
+
+ section symlinks
+ list str input
+ 'projects/mfd0816/VERSION1_DESIGN',
+ 'projects/mfd0816/VERSION1_INSTRUCTIONS'
+ str input_format 'data/$(%element%)'
+ str output_format '$(%element%)'
+
+ str exec '#!/usr/bin/env bash
+set -e
+
+mkdir -p \$(dirname $(%output%))
+
+rm $(%output%)
+ln --symbolic $(%input%) $(%output%)
'
end
end
diff --git a/data/index.sad b/data/index.sad
index c909f3e..25e7594 100644
--- a/data/index.sad
+++ b/data/index.sad
@@ -31,6 +31,12 @@ template this also looks like shit :)
* [demo] epoqe - Caturday Night Fever (music)
* [demo] epoqe - Eden Disorder (code support, music)
+{$end-section}
+{$begin-section} other
+{$sub-head} other
+
+* mfd0816 [github]
+
A fantasy CPU based on the intel 8088
{$end-section}
{$begin-section} c
{$sub-head} c
diff --git a/data/projects/mfd0816/VERSION1_DESIGN b/data/projects/mfd0816/VERSION1_DESIGN
new file mode 100644
index 0000000..607ce16
--- /dev/null
+++ b/data/projects/mfd0816/VERSION1_DESIGN
@@ -0,0 +1,568 @@
+ 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
diff --git a/data/projects/mfd0816/VERSION1_INSTRUCTIONS b/data/projects/mfd0816/VERSION1_INSTRUCTIONS
new file mode 100644
index 0000000..5d637a1
--- /dev/null
+++ b/data/projects/mfd0816/VERSION1_INSTRUCTIONS
@@ -0,0 +1,756 @@
+ MFD-0816 INSTRUCTION SET REFERENCE
+ November 2024
+
+CONTENTS
+────────────────────────────────────────────────────────────────────────────────
+
+ 1.... INSTRUCTION LISTING
+ 2.... INSTRUCTION SPECIFICATIONS
+ ..... LICENSE
+
+1. INSTRUCTION LISTING
+────────────────────────────────────────────────────────────────────────────────
+
+ 0x00..0x0f
+ ‾‾‾‾‾‾‾‾‾‾
+ ┌──────┬─────────────┬─────────────────────────┐
+ │ CODE │ NAME(S) │ DESCRIPTION │
+ ├──────┼─────────────┼─────────────────────────┤
+ │ 0x00 │ ADC │ Add with carry │
+ │ 0x01 │ ADD │ Add │
+ │ 0x02 │ AND │ Logical AND │
+ │ 0x03 │ BIN │ Read block from I/O Bus │
+ │ 0x04 │ BOT │ Write block to I/O Bus │
+ │ 0x05 │ CALL │ Call subroutine │
+ │ 0x06 │ │ Reserved │
+ │ 0x07 │ CMP │ Compare operands │
+ │ 0x08 │ DEC │ Decrement by 1 │
+ │ 0x09 │ DIV │ Unsigned divide │
+ │ 0x0a │ IDIV │ Signed divide │
+ │ 0x0b │ IMUL │ Signed multiply │
+ │ 0x0c │ IN │ Read byte from I/O Bus │
+ │ 0x0d │ INC │ Increment by 1 │
+ │ 0x0e │ INT │ Trigger interrupt │
+ │ 0x0f │ IRET │ Return from interrupt │
+ └──────┴─────────────┴─────────────────────────┘
+
+ Jcc - Jump (if condition is met)
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ ┌──────┬─────────────┬─────────────────────────┐
+ │ CODE │ NAME(S) │ DESCRIPTION │
+ ├──────┼─────────────┼─────────────────────────┤
+ │ 0x10 │ JMP │ Jump │
+ │ 0x11 │ JZ/JE │ Jump if ZF=1 │
+ │ 0x12 │ JG │ Jump if ZF=0 and NF=OF │
+ │ 0x13 │ JGE │ Jump if NF=OF │
+ │ 0x14 │ JL │ Jump if NF<>OF │
+ │ 0x15 │ JLE │ Jump if ZF=1 or NF<>OF │
+ │ 0x16 │ JC │ Jump if CF=1 │
+ │ 0x17 │ JS │ Jump if NF=1 │
+ │ 0x18 │ JNZ/JNE │ Jump if ZF=0 │
+ │ 0x19 │ JNC │ Jump if CF=0 │
+ │ 0x1a │ JNS │ Jump if NF=0 │
+ └──────┴─────────────┴─────────────────────────┘
+
+ 0x1b..0x2a
+ ‾‾‾‾‾‾‾‾‾‾
+ ┌──────┬─────────────┬─────────────────────────┐
+ │ CODE │ NAME(S) │ DESCRIPTION │
+ ├──────┼─────────────┼─────────────────────────┤
+ │ 0x1b │ LD │ Load word into register │
+ │ 0x1c │ MOV │ Move between registers │
+ │ 0x1d │ MUL │ Unsigned multiply │
+ │ 0x1e │ NEG │ Negate │
+ │ 0x1f │ NOP │ No operation │
+ │ 0x20 │ NOT │ Negate operand (logical)│
+ │ 0x21 │ OR │ Logical OR │
+ │ 0x22 │ OUT │ Write byte to I/O Bus │
+ │ 0x23 │ POP │ Pop word from stack │
+ │ 0x24 │ PUSH │ Push word to stack │
+ │ 0x25 │ RET │ Return from subroutine │
+ │ 0x26 │ ROL │ Rotate left │
+ │ 0x27 │ ROR │ Rotate right │
+ │ 0x28 │ SL │ Shift left │
+ │ 0x29 │ SR │ Shift right │
+ │ 0x2a │ ST │ Store register to memory│
+ └──────┴─────────────┴─────────────────────────┘
+
+ CLf - Clear flag
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ ┌──────┬─────────────┬─────────────────────────┐
+ │ CODE │ NAME(S) │ DESCRIPTION │
+ ├──────┼─────────────┼─────────────────────────┤
+ │ 0x2b │ CLO │ Clear OF in FL Register │
+ │ 0x2c │ CLC │ Clear CF in FL Register │
+ │ 0x2d │ CLZ │ Clear ZF in FL Register │
+ │ 0x2e │ CLN │ Clear NF in FL Register │
+ │ 0x2f │ CLI │ Clear IE in FL Register │
+ │ 0x30 │ CL? │ Reserved │
+ │ 0x31 │ CL? │ Reserved │
+ │ 0x32 │ CL? │ Reserved │
+ │ 0x33 │ CL? │ Reserved │
+ │ 0x34 │ CL? │ Reserved │
+ │ 0x35 │ CL? │ Reserved │
+ │ 0x36 │ CL? │ Reserved │
+ │ 0x37 │ CL? │ Reserved │
+ │ 0x38 │ CL? │ Reserved │
+ │ 0x39 │ CL? │ Reserved │
+ │ 0x3a │ CL? │ Reserved │
+ └──────┴─────────────┴─────────────────────────┘
+
+ STf - Set flag
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ ┌──────┬─────────────┬─────────────────────────┐
+ │ CODE │ NAME(S) │ DESCRIPTION │
+ ├──────┼─────────────┼─────────────────────────┤
+ │ 0x3b │ STO │ Set OF in FL Register │
+ │ 0x3c │ STC │ Set CF in FL Register │
+ │ 0x3d │ STZ │ Set ZF in FL Register │
+ │ 0x3e │ STN │ Set NF in FL Register │
+ │ 0x3f │ STI │ Set IE in FL Register │
+ │ 0x40 │ ST? │ Reserved │
+ │ 0x41 │ ST? │ Reserved │
+ │ 0x42 │ ST? │ Reserved │
+ │ 0x43 │ ST? │ Reserved │
+ │ 0x44 │ ST? │ Reserved │
+ │ 0x45 │ ST? │ Reserved │
+ │ 0x46 │ ST? │ Reserved │
+ │ 0x47 │ ST? │ Reserved │
+ │ 0x48 │ ST? │ Reserved │
+ │ 0x49 │ ST? │ Reserved │
+ │ 0x4a │ ST? │ Reserved │
+ └──────┴─────────────┴─────────────────────────┘
+
+ 0x4b..0x4d
+ ‾‾‾‾‾‾‾‾‾‾
+ ┌──────┬─────────────┬─────────────────────────┐
+ │ CODE │ NAME(S) │ DESCRIPTION │
+ ├──────┼─────────────┼─────────────────────────┤
+ │ 0x4b │ SUB │ Subtraction │
+ │ 0x4c │ TEST │ Logical compare (AND) │
+ │ 0x4d │ XOR │ Exclusive OR │
+ └──────┴─────────────┴─────────────────────────┘
+
+2. INSTRUCTION SPECIFICATIONS
+────────────────────────────────────────────────────────────────────────────────
+
+ 0x00 ADC
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Adds the value of ACL with the first operand and the carry flag and stores
+ the result in ACL. SF is modified to indicate if the result is
+ signed (SF = 1) or unsigned (SF = 0). Sets CF on carry for unsigned math,
+ OF on overflow for signed math and NF flag to indicate the sign of the
+ signed result. Sets ZF if the result is 0 (ACL = 0 && CF = 0 && OF = 0).
+
+ The first operand can be immediate, register immediate, direct,
+ register direct, indirect or register indirect.
+
+ Operation:
+
+ ACL := ACL + Operand1 + CF;
+
+ 0x01 ADD
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Adds the value of ACL with the first operand and stores the result in ACL.
+ Sets the NF flag to indicate the sign of the signed result.
+ Sets CF on carry for unsigned math, OF on overflow for signed math and the
+ NF flag to indicate the sign of the signed result. Sets ZF if the result
+ is 0 (ACL = 0 && CF = 0 && OF = 0).
+
+ The first operand can be immediate, register immediate, direct,
+ register direct, indirect or register indirect.
+
+ Operation:
+
+ ACL := ACL + Operand1;
+
+ Carry and Overflow example:
+
+ 0111b + 0001b = 0_1000b ; Signed int overflow, OF = 1 CF = 0
+ 0111b + 1001b = 1_0000b ; Unsigned int overflow, OF = 0 CF = 1
+ 0001b + 0001b = 0010b ; No overflow/carry, OF = 0 CF = 0
+
+ 0x02 AND
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Executes a logical AND with the current value of ACL and the first operand.
+ The result is then stored in ACL. Sets ZF if the result is 0, clears OF and
+ CF.
+
+ Operation:
+
+ ACL := ACL & Operand1;
+
+ 0x03 BIN
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Reads n units of data from the I/O Bus starting at the address indicated by
+ Operand 1 and stores it to the destination indicated by Operand 2.
+ The number of units read is indicated by the value of AL.
+
+ Both operand can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ for i := 1 to ACL do
+ io_read(Operand1 + i - 1, Operand2);
+ end
+
+ 0x04 BOT
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Writes n units of data to the I/O Bus starting at the address indicated by
+ Operand 1 and stores it to the destination indicated by Operand 2.
+ The number of units written is indicated by the value of AL.
+
+ Both operand can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ for i := 1 to ACL do
+ io_write(Operand1 + i - 1, Operand2);
+ end
+
+ 0x05 CALL
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Pushes the current value of IP to the stack and jumps to the address located
+ by Operand 1.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ push(IP);
+ IP := Operand1;
+
+ 0x07 CMP
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Subtracts Operand 1 from Operand 2 and sets the OF, CF and NF flags in the
+ same way as SUB. Discards the actual subtraction result.
+
+ Both operands can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ tmp := Operand1 - Operand2;
+ SUBSetFlags;
+
+ 0x08 DEC
+ ‾‾‾‾‾‾‾‾‾‾‾‾
+ Decrements the register given in Operand 1 by one.
+
+ Operation:
+
+ register := register - 1;
+
+ 0x09 DIV
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Divides the value of ACL by Operand 1 as an unsigned value and stores the
+ result in ACL.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ ACL := ACL / Operand1;
+
+ 0x0a IDIV
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Divides the value of ACL by Operand 1 as a signed value and stores the
+ result in ACL.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ ACL := ACL / Operand1;
+
+ 0x0b IMUL
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Multiplies the value of ACL by Operand 1 as a signed value and stores the
+ result in ACL. CF and OF are set if the most signficant bit,
+ including the sign bit, are carried over into AH. If the result fits into
+ AL, CF and OF are cleared.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ ACL := ACL * Operand 1;
+
+ if ACL = AL then
+ CF := 0;
+ OF := 0;
+ else
+ CF := 1;
+ OF := 0;
+ end
+
+ 0x0c IN
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Reads in one unit of data from the I/O bus at the address indicated by
+ Operand 1 and writes the result to the address indicated by Operand 2.
+
+ Both operands can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ io_read(Operand1, Operand2);
+
+ 0x0d INC
+ ‾‾‾‾‾‾‾‾‾‾‾‾
+ Increments the target register indicated by Operand 1 by one.
+
+ Operation:
+
+ register := register + 1;
+
+ 0x0e INT
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Triggers an interrupt with the id indicated by Operand1 if the IE flag is
+ set. If IE is clear, this instruction does nothing.
+
+ Operation:
+
+ if not IE then exit;
+
+ Interrupt(Operand1);
+
+ 0x0f IRET
+ ‾‾‾‾‾‾‾‾‾
+ Returns from an interrupt and sets IE. IID is also set to 0.
+ This instruction should only be executed from within an interrupt handler.
+
+ Operation:
+
+ IE := 1;
+ IID := 0;
+ pop(IP);
+
+ 0x10 JMP
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ IP := Operand1;
+
+ 0x11 JZ/JE
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if ZF is set.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if ZF = 1 then
+ IP := Operand1;
+ end
+
+ 0x12 JG
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if ZF is not set and NF is the
+ same as OF.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if ZF = 0 and (NF = OF) then
+ IP := Operand1;
+ end
+
+ 0x13 JGE
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if NF is the same as OF.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if NF = OF then
+ IP := Operand1;
+ end
+
+ 0x14 JL
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if NF is not the same as OF.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if NF <> OF then
+ IP := Operand1;
+ end
+
+ 0x15 JLE
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if ZF is set or NF is not the
+ same as OF.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if ZF = 1 or (NF <> OF) then
+ IP := Operand1;
+ end;
+
+ 0x16 JC
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if CF is set.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if CF = 1 then
+ IP := Operand1;
+ end
+
+ 0x17 JS
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if NF is set.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if NF = 1 then
+ IP := Operand1;
+ end
+
+ 0x18 JNZ/JNE
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if ZF is not set.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if ZF = 0 then
+ IP := Operand1;
+ end;
+
+ 0x19 JNC
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if CF is not set.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if CF = 0 then
+ IP := Operand1;
+ end;
+
+ 0x1a JNS
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Jumps to the address indicated by Operand 1 if NF is not set.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ if NF = 0 then
+ IP := Operand1;
+ end;
+
+ 0x1b LD
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Loads the value indicated by Operand 2 into the register indicated by
+ Operand 1.
+
+ Operand 2 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ register := Operand2;
+
+ 0x1c MOV
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Sets the register indicated by Operand 2 to the value indicated by
+ Operand 1.
+
+ Operand 1 can be immediate or register immediate.
+
+ 0x1d MUL
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Multiplies (unsigned) the value of ACL by Operand 1 and stores the result in
+ ACL. If the result fits into ACL, CF and OF are cleared otherwise both get
+ set.
+
+ Operand 2 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ 0x1e NEG
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+
+ Negates (Two's Complement) the value of Operand 1 and stores the result
+ in Operand 1.
+
+ Operand 1 can be register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ Operand1 := 0 - Operand1;
+
+ 0x1f NOP
+ ‾‾‾‾‾‾‾‾
+
+ Does nothing.
+
+ 0x20 NOT
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Negates (One's Complement) the value of Operand 1 and stores the result in
+ Operand 1.
+
+ Operand 1 can be direct, register direct, indirect or register indirect.
+
+ Operation:
+
+ Operand1 := 0 - Operand1;
+
+ 0x21 OR
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Performs a logical OR with the value of ACL and Operand 1 and stores the
+ result in ACL.
+
+ Operand 1 can be direct, register direct, indirect or register indirect.
+
+ Operation:
+
+ ACL := ACL or Operand1;
+
+ 0x22 OUT
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Writes in one unit of data to the I/O bus to the address indicated by
+ Operand 2 from the address indicated by Operand 1.
+
+ Both operands can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ io_write(Operand2, Operand1);
+
+ 0x23 POP
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Pops the top value from the stack and writes it to the location indicated by
+ Operand 1. Increments SP by 2.
+
+ Operand 1 can be register immediate, direct, register direct, indirect
+ or register indirect.
+
+ Operation:
+
+ Operand1 := *SP;
+ SP := SP + 2;
+
+ 0x24 PUSH
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Pushes the value indicated by Operand 1 to the top of the stack. Decrements
+ SP by 2.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ SP := SP - 2;
+ *SP := Operand1;
+
+ 0x25 RET
+ ‾‾‾‾‾‾‾‾
+ Returns from a subroutine.
+
+ Operation:
+
+ pop(IP);
+
+ 0x26 ROL
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Rotates the value indicated by Operand 1 left by the amount of times
+ indicated by Operand 2 and stores the result in Operand 1.
+
+ Operand 1 can be register immediate, direct, register direct, indirect or
+ register indirect.
+
+ Operand 2 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ tmp := Operand1 shl Operand2;
+ Operand1 := tmp or (tmp shr 16 and 0xff)
+
+ 0x27 ROR
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Rotates the value indicated by Operand 1 right by the amount of times
+ indicated by Operand 2 and stores the result in Operand 1.
+
+ Operand 1 can be register immediate, direct, register direct, indirect or
+ register indirect.
+
+ Operand 2 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ tmp := (Operand1 shl 8) shr Operand2;
+ Operand1 := (Operand1 shr Operand2) or ((tmp and 0xff) shl 8)
+
+ 0x28 SL
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Shifts the value indicated by Operand 1 left by the amount indicated by
+ Operand 2 and stores the result in Operand 1.
+
+ Operand 1 can be register immediate, direct, register direct, indirect or
+ register indirect.
+
+ Operand 2 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ Operand1 := Operand1 shl Operand2;
+
+ 0x29 SR
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Shifts the value indicated by Operand 1 right by the amount indicated by
+ Operand 2 and stores the result in Operand 1.
+
+ Operand 1 can be register immediate, direct, register direct, indirect or
+ register indirect.
+
+ Operand 2 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ Operand1 := Operand1 shr Operand2;
+
+ 0x2a ST
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Stores the value indicated by Operand 1 to the place in memory indicated by
+ Operand 2.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operand 2 can be direct, register direct, indirect or register indirect.
+
+ Operation:
+
+ Operand2 := Operand1;
+
+ 0x2b CLO
+ ‾‾‾‾‾‾‾‾
+ Clears the overflow flag.
+
+ 0x2c CLC
+ ‾‾‾‾‾‾‾‾
+ Clears the carry flag.
+
+ 0x2d CLZ
+ ‾‾‾‾‾‾‾‾
+ Clears the zero flag.
+
+ 0x2e CLN
+ ‾‾‾‾‾‾‾‾
+ Clears the negative flag.
+
+ 0x2f CLI
+ ‾‾‾‾‾‾‾‾
+ Clears the interrupt enable flag.
+
+ 0x30..0x3a CL?
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ This range of instructions is currently invalid.
+
+ 0x3b STO
+ ‾‾‾‾‾‾‾‾
+ Sets the overflow flag.
+
+ 0x3c STC
+ ‾‾‾‾‾‾‾‾
+ Sets the carry flag.
+
+ 0x3d STZ
+ ‾‾‾‾‾‾‾‾
+ Sets the zero flag.
+
+ 0x3e STN
+ ‾‾‾‾‾‾‾‾
+ Sets the negative flag.
+
+ 0x3f STI
+ ‾‾‾‾‾‾‾‾
+ Sets the interrupt enable flag.
+
+ 0x40..0x4a ST?
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ This range of instructions is currently invalid.
+
+ 0x4b SUB
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Subtracts the value indacted by Operand 1 from the value of ACL and stores
+ the result in ACL.
+ Sets CF on carry for unsigned math, OF on overflow for signed math and the
+ NF flag to indicate the sign of the signed result. Sets ZF if the result
+ is 0 (ACL = 0 && CF = 0 && OF = 0).
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ 0x4c TEST
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Executes a logical AND with the value indicated by Operand 1 and the value
+ indicated by Operand 2. The result of the AND is discarded. Sets ZF if the
+ result is 0, clears OF and CF.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ ANDSetFlags(ACL & Operand1);
+
+ 0x4d XOR
+ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
+ Executes a XOR operation on the value of ACL with the value indicated by
+ Operand 1. Stores the result in ACL.
+
+ Operand 1 can be immediate, register immediate, direct, register direct,
+ indirect or register indirect.
+
+ Operation:
+
+ ACL := ACL ^ Operand1;
+
+LICENSE
+────────────────────────────────────────────────────────────────────────────────
+
+ MFD0816 INSTRUCTIONS by Marie Eckert is licensed under CC BY-SA 4.0,
+ see
diff --git a/data/projects/mfd0816/index.sad b/data/projects/mfd0816/index.sad
new file mode 100644
index 0000000..52ae216
--- /dev/null
+++ b/data/projects/mfd0816/index.sad
@@ -0,0 +1,21 @@
+{$start}
+{$title} mfd0816
+
+{$begin-section} about
+{$head} about
+
+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
+
+{$begin-section} links
+{$sub-head} links
+* [Version 1] Design
+* [Version 1] Instruction Set Reference
+* GitHub
+{$end-section}
+{$end-section}
diff --git a/test.css b/test.css
index 4740db5..b02b382 100644
--- a/test.css
+++ b/test.css
@@ -4,7 +4,6 @@
html,
body {
- height: 100%;
margin: 0;
padding: 0;
}