add basic mfd0816 site

This commit is contained in:
Marie 2024-12-04 19:52:05 +01:00
parent 9f29c3b52c
commit ecf8227b53
6 changed files with 1375 additions and 3 deletions

View file

@ -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

View file

@ -31,6 +31,12 @@ template this also looks like shit :)
* [demo] epoqe - <a href="https://www.pouet.net/prod.php?which=94085">Caturday Night Fever</a> (music)<br>
* [demo] epoqe - <a href="https://www.pouet.net/prod.php?which=93178">Eden Disorder</a> (code support, music)<br>
{$end-section}
{$begin-section} other
{$sub-head} other
* <a href="/projects/mfd0816/index.html">mfd0816</a>&ensp;<a class="git-link" href="https://github.com/FelixEcker/mfd0816">[github]</a><br>
<div class="description"> &emsp; A fantasy CPU based on the intel 8088 </div>
{$end-section}
{$begin-section} c
{$sub-head} c

View file

@ -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 <https://creativecommons.org/licenses/by-sa/4.0/>

View file

@ -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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r>
‾‾‾‾‾‾‾‾‾‾‾‾
Decrements the register given in Operand 1 by one.
Operation:
register := register - 1;
0x09 DIV <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r>
‾‾‾‾‾‾‾‾‾‾‾‾
Increments the target register indicated by Operand 1 by one.
Operation:
register := register + 1;
0x0e INT <imm>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm> <r>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Sets the register indicated by Operand 2 to the value indicated by
Operand 1.
Operand 1 can be immediate or register immediate.
0x1d MUL <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/m> <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m> <m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <r/imm/m>
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
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 <https://creativecommons.org/licenses/by-sa/4.0/>

View file

@ -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 <br>
* 16-bit word <br>
* 8-bit I/O bus <br>
* 4x 16-bit general purpose register <br>
{$begin-section} links
{$sub-head} links
* <a href="/projects/mfd0816/VERSION1_DESIGN">[Version 1] Design</a><br>
* <a href="/projects/mfd0816_VERSION1_INSTRUCTIONS">[Version 1] Instruction Set Reference </a><br>
* <a href="https://github.com/FelixEcker/mfd0816">GitHub</a><br>
{$end-section}
{$end-section}

View file

@ -4,7 +4,6 @@
html,
body {
height: 100%;
margin: 0;
padding: 0;
}