Skip to content

mikeakohn/micro86

Repository files navigation

micro86

This is an implementation of 32 bit Intel x86 in an FPGA. The board being used here is an iceFUN with a Lattice iCE40 HX8K FPGA.

https://www.mikekohn.net/micro/micro_x86_68000_fpga.php

This only implements the important instructions, but does include all the strange addressing modes. Example of some instructions:

  • 32, 16, 8 bit register access.
  • All the standard ALU and mov instructions with their addressing modes.
  • The push and pop only work with 32 bit registers.

The memory model is 8 bit, so reading and writing 32 bits takes 4 memory cycles. Kind of slow, but easier to implement.

Implemnted Instructions

Here's a list of instructions that are implemented. There are possibly others missing here.

adc
add
and
call
clc
cbw
cmc
cmp
cwde
dec (reg only, only 16 and 32 bit)
inc (reg only, only 16 and 32 bit)
jcc
jmp
lea
mov
neg
or
pop
push
pushf
ret
sbb
sha
shl
shr
stc
sub
xor
test

Shifts only work directly on registers.

Memory Map

This implementation of the Intel x86 has 4 banks of memory.

  • Bank 0: RAM (4096 bytes)
  • Bank 1: ROM (4096 bytes loaded from rom.txt)
  • Bank 2: Peripherals
  • Bank 3: RAM (4096 bytes)

On start-up by default, the chip will load a program from a AT93C86A 2kB EEPROM with a 3-Wire (SPI-like) interface but wll run the code from the ROM. To start the program loaded to RAM, the program select button needs to be held down while the chip is resetting.

The peripherals area contain the following:

  • 0x8000: input from push button
  • 0x8001: SPI TX
  • 0x8002: SPI RX
  • 0x8003: SPI CTRL
  • 0x8008: ioport0 output (in my test case only 1 pin is connected)
  • 0x8009: MIDI note value (60-96) to play a tone on the speaker or 0 to stop
  • 0x800a: iport1

x86 Details

Registers

NUM  32    16    8
------------------
000 eax  / ax / al
001 ecx  / cx / cl
010 edx  / dx / dl
011 ebx  / bx / bl
100 esp  / sp / ah
101 ebp  / bp / ch
110 esi  / si / dh
111 edi  / di / bh

Addressing Modes

A typical x86 instruction has an 8 bit opcode followed by an 8 bit mode byte possibly followed by data or SIB byte. If the destination register is 16 bit, it is prefixed by 0x66.

PREFIX | MOD R/M | SIB | DISPLACEMENT | IMMEDIATE

Displacement and immediate can be 1, 2, or 4 bytes.

Typical opcode encoding:

7 6 5 4 3 2 | 1 | 0
   OPCODE   | d | s

The bit in position 1 is the direction bit (which of the operands is the source / destination) and the bottom bit tells the size (32 or 8 bit). Again, if the instruction should run in 16 bit mode, a 0x66 prefix comes first. Not all instructions actually use this encoding.

The MOD R/M encoding is:

7 6 | 5 4 3 | 2 1 0
MOD    REG     R/M

The upper 2 bits (the MOD bits) tells the addressing mode of the instruction:

00: Register Indirect unless: R/M=101 Displacement only.
01: 1 byte signed displacement (-128 to 127)
10: 4 byte signed displacement
11: Register to register.

For all modes but 11, R/M=100 (ESP) is special.

MOD 11 example is:

                        OP    DS  MOD REG R/M
mov ebx, edx   89 d3   100010 01  11  010 011

MOD 01 example is:

                              OP    DS  MOD REG R/M   offset
mov ebx,[edx+0x4] 8B 5a 04   100110 11  01  011 010   0000 0100
mov [edx+0x4],ebx 89 5a 04   100110 01  01  011 010   0000 0100

MOD 01 R/M=100 example is:

mov edx,[ebx+ecx*4+0x64] 8b 54 8b 64
mov [ebx+ecx*4+0x64],edx 89 54 8b 64
 
                          |    SIB      |
         DS  MOD REG R/M  SCALE INDEX BASE  OFFSET
  100010 11  01  010 100  10     001  011   0x64
  100010 01  01  010 100  10     001  011   0x64

MOD 10 example is:

                                        OP    DS  MOD REG R/M
mov ebx,[edx+0x100] 8b 9a 00 01 00 00  100010 11  10  011 010 [4 byte off]
mov [edx+0x100],ebx 89 9a 00 01 00 00  100010 01  10  011 010 [4 byte off]

MOD 10 R/M=100 example is:

mov edx,[ebx+ecx*4+0x3e8] 8b 94 8b e8 03 00 00
mov [ebx+ecx*4+0x3e8],edx 89 94 8b e8 03 00 00

                          |    SIB      |
         DS  MOD REG R/M  SCALE INDEX BASE  OFFSET
  100010 11  10  010 100  10     001  011   0xe8 0x03 0x00 0x00
  100010 01  10  010 100  10     001  011   0xe8 0x03 0x00 0x00

MOD 00 R/M=000 example:

                        OP    DS  MOD REG R/M
mov ebx,[edx]   8b 1a  100010 11  00  011 010
mov [edx],ebx   89 1a  100010 01  00  011 010

MOD 00 R/M=100 example:

                                                 |    SIB      |
                          OP    DS  MOD REG R/M  SCALE INDEX BASE 
mov ebx,[esp]: 8b 1c 24  100010 11  00  011 100  00     100  100
mov [esp],ebx: 89 1c 24  100010 01  00  011 100  00     100  100

                                                    |    SIB      |
                             OP    DS  MOD REG R/M  SCALE INDEX BASE 
mov edx,[ebx+edx] 8b 14 13  100010 11  00  010 100  00     010  011
mov [ebx+edx],edx 89 14 13  100010 01  00  010 100  00     010  011

                                                      |    SIB      |
                               OP    DS  MOD REG R/M  SCALE INDEX BASE 
mov edx,[ebx+ecx*4] 8b 14 8b  100010 11  00  010 100  10    001   011
mov [ebx+ecx*4],edx 89 14 8b  100010 01  00  010 100  10    001   011

MOD 00 R/M=101 example:

mov [dword 0x80],edx   89 15 80 00 00 00
mov [dword 0x1000],edx 89 15 00 10 00 00

  OP     DS  MOD REG R/M
  100010 01  00  010 101  0xe8 0x03 0x00 0x00
  100010 01  00  010 101  0xe8 0x03 0x00 0x00

Other examples:

// add edx, [esi]:      0x03,0x16
// add dx,  [esi]: 0x66,0x03,0x16
// add dl,  [esi]:      0x02,0x16

As bits:

prefix            dw  MD REG R/M
    -      0000 0011  00 010 110
0110 0110  0000 0011  00 010 110
    -      0000 0010  00 010 110

Example Instructions

mov eax, [ebx+0x4000]
mov ebx, 0xf1
mov [0x0004], ebx
mov eax, [0x0004]
lea eax, [ebx+eax*2]
call eax
test ebx, 1
jz skip_led
call led_on
hlt
ret
push ebx
rol eax, cl
shr eax, 5

About

Intel x86 (32 bit with unneeded instructions removed) in an FPGA.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published