Fixed register addressing bug, mem read endianness, cleaned up code and added a provisional project logo

This commit is contained in:
(Tim) Efthimis Kritikos 2023-02-19 00:20:53 +00:00
parent 82bd859874
commit fd4a9b5442
16 changed files with 297 additions and 358 deletions

View File

@ -6,39 +6,30 @@ Instructions vary from 1 to 6 bytes.
| ---------------- | --------- | ---- | ---- | ---- | ---- |
| Opcode | D bit | W bit | MOD | REG | R/M |
* **D**-bit : the register specified in the Register ID field is a source register (D = 0) or destination register (D =1).
* **W**-bit : specifies whether the instruction is a byte instruction (W = 0) or a word instruction (W = 1).
* **D**-bit : The register specified in REG field is a source register (D = 0) or destination register (D =1).
* **W**-bit : Specifies whether the instruction operates on bytes (W = 0) or words (W = 1).
On some instructions:
* **S**-bit : An 8-bit 2's complement number. It can be extended to a 16-bit 2s complement number depending on the W-bit by making all of the bits in the higher-order byte equal the most significant bit in the low order byte. This is known as sign extension.
* **S**-bit : An 8-bit 2's complement number. It can be extended to a 16-bit 2s complement number internally depending on the W-bit
| S | W | Operation |
| --- | --- | -------------- |
| --- | --- | ----------------------------------------------------- |
| 0 | 0 | 8bit operation |
| 0 | 1 | 16bit operation with 16bit immediate operand |
| 1 | 0 | invalid? |
| 1 | 1 | 16bit operation with a sign extended 8bit immediate operand
| 1 | 1 | 8bit immediate operand extended to 16 signed internally|
* **V**-bit : V-bit decides the number of shifts for rotate and shift instructions. If V = 0, then count = 1; if V = 1, the count is in CL register. For example, if V = 1 and CL = 2 then shift or rotate instruction shifts or rotates 2-bits
* **Z**-bit : Used as a compare bit with the zero flag in conditional repeat and loop instructions. ex branch if zero is set or clear.
No instruction has parts of its opcode past the first 2 bytes I.e. all bytes after the first two are additional data bytes
| Register ID / REG | Register Name |
|:-------------------:|:-------------:|
| 0 0 0 | AL AX |
| 0 0 1 | CL CX |
| 0 1 0 | DL DX |
| 0 1 1 | BL BX |
| 1 0 0 | AH SP |
| 1 0 1 | CH BP |
| 1 1 0 | DH SI |
| 1 1 1 | BH DI |
The second byte of the instruction usually identifies the instruction's operands. The **MOD** (mode) field weather or not the operands is in memory or if both are registers. In some instructions like the immediate-to-memory type the **REG** field is used as an extension of the opcode. The function of **R/M** depends on how MOD. if MOD=11 (register-register mode) then **R/M** specifies the second Register, otherwise it specifies how the effective address in memory is calculated
The second byte of the instruction usually identifies the instruction's operands. The **MOD** (mode) field weather on of the operands is in memory or if both are registers. In some instructions like the immediate-to-memory type the **REG** field is used as an extension of the opcode. The encoding of **R/M** depends on how MOD is set. if MOD=11 (register-register mode) then **R/M** specifies the second Register using the Register ID. otherwise it specifies how the effective address in memory is calculated
|R/M | Memory Mode with no displacement [ 0 0 ] | Memory mode with 8 bit displacement [ 0 1 ] | Memory Mode with 16 bit displacement [ 1 0 ] | Register Mode [ 1 1 ] W = 0| Register Mode [ 1 1 ] W = 1 |
|R/M | Memory indirect with no displacement [ 0 0 ] | Memory indirect with 8 bit displacement [ 0 1 ] | Memory indirect with 16 bit displacement [ 1 0 ] | Register Mode [ 1 1 ] W = 0| Register Mode [ 1 1 ] W = 1 |
|---- | ---------------------------------------- | ------------------------------------------- | -------------------------------------------- | --------------------------- | --------------------------- |
|000 | [BX] + [SI] | [BX] + [SI] + d8 | [BX] + [SI] + d16 | AL | AX |
|001 | [BX] + [DI] | [BX] + [DI] + d8 | [BX] + [DI] + d16 | CL | CX |
@ -58,3 +49,27 @@ Example instructions:
|fe c0 | inc %al | increment register al |
|ff c0 | inc %ax | increment register ax |
|40 | inc %ax | increment register ax |
### Flags
Flag register:
|.. |.. |.. |.. | O | D | I | T | S | Z |.. | A |.. | P |.. | C |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
* C - Carry flag : carry out or borrow into the high order bit (8bit/16bit)
* P - Parity flag : set if result has even parity
* A - Auxiliary flag : carry out from the low nibble to the high nibble or an equiv borrow. Used by decimal arithmetic instructions
* Z - Zero flag : Set when result of Operation is zero
* S - Sign flag : set if the high order bit of the result is 1. ie the sign of the result
* T - Trap flag : Set the CPU into single step mode where it generates an interrupt after each instruction
* I - Interrupt flag : 0: interrupts are masked
* D - Direction flag : 1: string instructions decrement 0: they increment
* O - Overflow flag : set on arithmetic overflow

View File

@ -1,4 +1,6 @@
# 9086
<img width="186" height="70" align="left" style="float: left; margin: 0 10px 0 0;" alt="9086 logo" src="readme_files/9086_design1.svg">
#
A CPU that aims to be binary compatible with the 8086 and with as many optimisations as possible

View File

@ -1,4 +1,4 @@
SOURCE=$(shell ls |grep asm$)
SOURCE=brainfuck.asm brainfuck_mandelbrot.asm
BINARIES=$(subst .asm,.txt,${SOURCE})
BUILD_FILES=${BINARIES}
BUILD_FILES+=$(subst .asm,.memdump,${SOURCE})
@ -7,6 +7,9 @@ BUILD_FILES+=$(subst .asm,.bin,${SOURCE})
all: ${BINARIES}
brainfuck.bin: brainfuck_interpreter_v0.asm
brainfuck_mandelbrot.bin: brainfuck_interpreter_v0.asm
include ../common.mk
clean:

View File

@ -1,122 +1,5 @@
; brainfuck.asm - Naive and unoptimised implementation of a brainfuck interpreter
;
; This file is part of the 9086 project.
;
; Copyright (c) 2023 Efthymios Kritikos
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
INCLUDE brainfuck_interpreter_v0.asm
mov si,#prog
mov BX,#data
mov CX,#bracket
dec si
INTERPRET:
inc si
mov al,[si]
cmp al,#'+
jz WAS_PLUS
cmp al,#'-
jz WAS_MINUS
cmp al,#'>
jz WAS_MR
cmp al,#'<
jz WAS_ML
cmp al,#'[
jz WAS_PL
cmp al,#']
jz WAS_PR
cmp al,#'.
jz WAS_PRINT
jmp PROG_END
WAS_PLUS:
inc BYTE [BX]
JMP INTERPRET
WAS_MINUS:
dec BYTE [BX]
JMP INTERPRET
WAS_MR:
inc bx
JMP INTERPRET
WAS_ML:
dec bx
JMP INTERPRET
WAS_PL:
MOV AL,[BX]
cmp AL,#0
jz SKIP_CODE_BLOCK
;have to enter loop
MOV AX,SI
inc CX
inc CX
MOV SI,CX
mov [SI],AX
mov SI,AX
JMP INTERPRET
SKIP_CODE_BLOCK:
;have to skip loop
MOV DX,#0
SKIP_LOOP:
INC SI
mov AL,[SI]
CMP AL,#']
JZ WAS_CLOSE1
CMP AL,#'[
JZ WAS_OPEN1
JMP SKIP_LOOP
WAS_CLOSE1:
CMP DX,#0
JZ INTERPRET
DEC DX
JMP SKIP_LOOP
WAS_OPEN1:
INC DX
JMP SKIP_LOOP
WAS_PR:
mov AL,[BX]
cmp AL,#0
JZ EXIT_PR
MOV SI,CX
mov ax,[SI]
mov si,ax
JMP INTERPRET
EXIT_PR:
DEC CX
DEC CX
jmp INTERPRET
WAS_PRINT:
mov ah, #0x02
MOV DL,[BX]
int #0x21
JMP INTERPRET
PROG_END:
hlt
bracket: .BLKB 280
data: .BLKB 560
prog:
.ASCII '++++++++++[>+>+++>+++++++>++++++++++<<<<-]>>>++.>+.+++++++..+++.<<++.>+++++++++++++++.>.+++.------.--------.<<.>>++.+++++'
.ASCII '+++++++.---.--.<<.>---------------------.>+++++.-----------------.++++++++.+++++.--------.+++++++++++++++.---------------'

View File

@ -0,0 +1,129 @@
; brainfuck_interpreter_v0.asm - Naive and unoptimised implementation of a brainfuck interpreter
;
; This file is part of the 9086 project.
;
; Copyright (c) 2023 Efthymios Kritikos
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
mov bx,#bootup_msg
mov ah,#0x02
bootup_print:
mov dl,[bx]
int #0x21
inc bx
cmp dl,#0x0A
jne bootup_print
mov si,#prog
mov BX,#data
mov CX,#bracket
dec si
INTERPRET:
inc si
mov al,[si]
cmp al,#'+
jz WAS_PLUS
cmp al,#'-
jz WAS_MINUS
cmp al,#'>
jz WAS_MR
cmp al,#'<
jz WAS_ML
cmp al,#'[
jz WAS_PL
cmp al,#']
jz WAS_PR
cmp al,#'.
jz WAS_PRINT
jmp PROG_END
WAS_PLUS:
inc BYTE [BX]
JMP INTERPRET
WAS_MINUS:
dec BYTE [BX]
JMP INTERPRET
WAS_MR:
inc bx
JMP INTERPRET
WAS_ML:
dec bx
JMP INTERPRET
WAS_PL:
MOV AL,[BX]
cmp AL,#0
jz SKIP_CODE_BLOCK
;have to enter loop
MOV AX,SI
inc CX
inc CX
MOV SI,CX
mov [SI],AX
mov SI,AX
JMP INTERPRET
SKIP_CODE_BLOCK:
;have to skip loop
MOV DX,#0
SKIP_LOOP:
INC SI
mov AL,[SI]
CMP AL,#']
JZ WAS_CLOSE1
CMP AL,#'[
JZ WAS_OPEN1
JMP SKIP_LOOP
WAS_CLOSE1:
CMP DX,#0
JZ INTERPRET
DEC DX
JMP SKIP_LOOP
WAS_OPEN1:
INC DX
JMP SKIP_LOOP
WAS_PR:
mov AL,[BX]
cmp AL,#0
JZ EXIT_PR
MOV SI,CX
mov ax,[SI]
mov si,ax
JMP INTERPRET
EXIT_PR:
DEC CX
DEC CX
jmp INTERPRET
WAS_PRINT:
mov ah, #0x02
MOV DL,[BX]
int #0x21
JMP INTERPRET
PROG_END:
hlt
bootup_msg: .ASCII 'Brainfuck interpeter v0\n'
bracket: .BLKB 280
data: .BLKB 560

View File

@ -1,124 +1,7 @@
; brainfuck.asm - Naive and unoptimised implementation of a brainfuck interpreter
;
; This file is part of the 9086 project.
;
; Copyright (c) 2023 Efthymios Kritikos
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
INCLUDE brainfuck_interpreter_v0.asm
mov si,#prog
mov BX,#data
mov CX,#bracket
dec si
INTERPRET:
inc si
mov al,[si]
cmp al,#'+
jz WAS_PLUS
cmp al,#'-
jz WAS_MINUS
cmp al,#'>
jz WAS_MR
cmp al,#'<
jz WAS_ML
cmp al,#'[
jz WAS_PL
cmp al,#']
jz WAS_PR
cmp al,#'.
jz WAS_PRINT
jmp PROG_END
WAS_PLUS:
inc BYTE [BX]
JMP INTERPRET
WAS_MINUS:
dec BYTE [BX]
JMP INTERPRET
WAS_MR:
inc bx
JMP INTERPRET
WAS_ML:
dec bx
JMP INTERPRET
WAS_PL:
MOV AL,[BX]
cmp AL,#0
jz SKIP_CODE_BLOCK
;have to enter loop
MOV AX,SI
inc CX
inc CX
MOV SI,CX
mov [SI],AX
mov SI,AX
JMP INTERPRET
SKIP_CODE_BLOCK:
;have to skip loop
MOV DX,#0
SKIP_LOOP:
INC SI
mov AL,[SI]
CMP AL,#']
JZ WAS_CLOSE1
CMP AL,#'[
JZ WAS_OPEN1
JMP SKIP_LOOP
WAS_CLOSE1:
CMP DX,#0
JZ INTERPRET
DEC DX
JMP SKIP_LOOP
WAS_OPEN1:
INC DX
JMP SKIP_LOOP
WAS_PR:
mov AL,[BX]
cmp AL,#0
JZ EXIT_PR
MOV SI,CX
mov ax,[SI]
mov si,ax
JMP INTERPRET
EXIT_PR:
DEC CX
DEC CX
jmp INTERPRET
WAS_PRINT:
mov ah, #0x02
MOV DL,[BX]
int #0x21
JMP INTERPRET
PROG_END:
hlt
bracket: .BLKB 280
data: .BLKB 560
;prog db '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.f'
prog:.ASCII '+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[['
prog:
.ASCII '+++++++++++++[->++>>>+++++>++>+<<<<<<]>>>>>++++++>--->>>>>>>>>>+++++++++++++++[['
.ASCII '>>>>>>>>>]+[<<<<<<<<<]>>>>>>>>>-]+[>>>>>>>>[-]>]<<<<<<<<<[<<<<<<<<<]>>>>>>>>[-]+'
.ASCII '<<<<<<<+++++[-[->>>>>>>>>+<<<<<<<<<]>>>>>>>>>]>>>>>>>+>>>>>>>>>>>>>>>>>>>>>>>>>>'
.ASCII '>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>>'

Binary file not shown.

View File

@ -0,0 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -0.5 112 42" shape-rendering="crispEdges">
<path stroke="#346524" d="M0 0h5M9 0h3M16 0h3M23 0h3M30 0h3M37 0h3M44 0h17M65 0h3M72 0h3M79 0h3M86 0h10M100 0h6M110 0h2M0 1h5M9 1h3M16 1h3M23 1h3M30 1h3M37 1h3M44 1h4M57 1h4M65 1h3M72 1h3M79 1h3M86 1h10M100 1h6M110 1h2M0 2h5M9 2h3M16 2h3M23 2h3M30 2h3M37 2h3M44 2h3M58 2h3M65 2h3M72 2h3M79 2h3M86 2h3M93 2h3M100 2h6M110 2h2M0 3h5M9 3h3M16 3h3M23 3h3M30 3h3M37 3h3M44 3h3M58 3h3M65 3h3M72 3h3M79 3h3M86 3h3M93 3h3M100 3h6M110 3h2M0 4h2M103 4h3M110 4h2M0 5h2M110 5h2M0 6h2M110 6h2M0 7h2M110 7h2M0 8h2M109 8h3M0 9h2M103 9h9M0 10h2M103 10h9M0 11h2M0 12h2M0 13h2M0 14h2M0 15h2M103 15h9M0 16h2M103 16h9M0 17h2M0 18h2M0 19h3M0 20h3M0 21h3M103 21h9M0 22h3M103 22h9M0 23h3M0 24h2M0 25h2M0 26h2M0 27h2M103 27h9M0 28h2M103 28h9M0 29h2M0 30h2M0 31h2M0 32h2M0 33h2M103 33h9M0 34h2M103 34h9M0 35h2M103 35h9M0 36h2M103 36h3M110 36h2M0 37h2M103 37h2M111 37h1M0 38h2M111 38h1M0 39h5M9 39h3M16 39h3M23 39h3M30 39h3M37 39h3M44 39h3M51 39h3M58 39h3M65 39h3M72 39h3M79 39h3M86 39h3M93 39h3M111 39h1M0 40h5M9 40h3M16 40h3M23 40h3M30 40h3M37 40h3M44 40h3M51 40h3M58 40h3M65 40h3M72 40h3M79 40h3M86 40h3M93 40h3M111 40h1M0 41h5M9 41h88M110 41h2" />
<path stroke="#6daa2c" d="M5 0h4M12 0h4M19 0h4M26 0h4M33 0h4M40 0h4M61 0h4M68 0h4M75 0h4M82 0h4M96 0h4M106 0h4M5 1h4M12 1h4M19 1h4M26 1h4M33 1h4M40 1h4M48 1h9M61 1h4M68 1h4M75 1h4M82 1h4M96 1h4M106 1h4M51 2h3M106 2h4M51 3h3M106 3h4M106 4h4M103 5h7M103 6h7M103 7h7M103 8h6M103 11h9M103 12h9M103 13h9M103 14h9M103 17h9M103 18h9M103 19h9M103 20h9M103 23h9M103 24h9M103 25h9M103 26h9M103 29h9M103 30h9M103 31h9M103 32h9M106 36h4M105 37h2M109 37h2M103 38h3M110 38h1M100 39h6M110 39h1M100 40h7M109 40h2M5 41h4M97 41h13" />
<path stroke="#deeed6" d="M5 2h4M12 2h4M19 2h4M26 2h4M33 2h4M40 2h4M47 2h4M54 2h4M61 2h4M68 2h4M75 2h4M82 2h4M89 2h4M96 2h4M5 3h4M12 3h4M19 3h4M26 3h4M33 3h4M40 3h4M47 3h4M54 3h4M61 3h4M68 3h4M75 3h4M82 3h4M89 3h4M96 3h4M5 39h4M12 39h4M19 39h4M26 39h4M33 39h4M40 39h4M47 39h4M54 39h4M61 39h4M68 39h4M75 39h4M82 39h4M89 39h4M96 39h4M5 40h4M12 40h4M19 40h4M26 40h4M33 40h4M40 40h4M47 40h4M54 40h4M61 40h4M68 40h4M75 40h4M82 40h4M89 40h4M96 40h4" />
<path stroke="#4e4a4e" d="M2 4h101M2 5h1M102 5h1M2 6h1M102 6h1M2 7h1M102 7h1M2 8h1M102 8h1M2 9h1M102 9h1M2 10h1M102 10h1M2 11h1M102 11h1M2 12h1M102 12h1M2 13h1M102 13h1M2 14h1M102 14h1M2 15h1M102 15h1M2 16h1M102 16h1M2 17h1M93 17h3M102 17h1M2 18h3M91 18h2M96 18h2M102 18h1M5 19h1M91 19h1M97 19h1M102 19h1M6 20h1M90 20h1M98 20h1M102 20h1M6 21h1M90 21h1M98 21h1M102 21h1M90 22h1M102 22h1M102 23h1M102 24h1M2 25h1M102 25h1M2 26h1M102 26h1M2 27h1M102 27h1M2 28h1M102 28h1M2 29h1M102 29h1M2 30h1M102 30h1M2 31h1M102 31h1M2 32h1M5 32h3M102 32h1M2 33h1M4 33h1M8 33h1M102 33h1M2 34h1M4 34h1M8 34h1M102 34h1M2 35h1M102 35h1M2 36h1M102 36h1M2 37h1M102 37h1M2 38h101" />
<path stroke="#756f75" d="M3 5h99M3 6h99M3 7h99M3 8h15M29 8h7M47 8h7M65 8h7M85 8h17M3 9h14M30 9h5M48 9h5M66 9h5M85 9h17M3 10h13M31 10h3M49 10h3M67 10h3M84 10h18M3 11h13M31 11h3M49 11h3M67 11h3M83 11h19M3 12h13M19 12h9M31 12h3M37 12h8M49 12h3M56 12h7M67 12h3M74 12h28M3 13h13M19 13h9M31 13h3M37 13h7M49 13h3M55 13h9M67 13h3M73 13h29M3 14h13M19 14h9M31 14h3M37 14h7M49 14h3M55 14h9M67 14h3M73 14h29M3 15h13M19 15h9M31 15h3M37 15h6M49 15h3M55 15h9M67 15h3M73 15h29M3 16h13M19 16h9M31 16h3M37 16h6M49 16h3M55 16h9M67 16h3M73 16h29M3 17h13M19 17h9M31 17h3M37 17h5M45 17h1M49 17h3M55 17h9M67 17h3M73 17h20M96 17h6M5 18h11M19 18h9M31 18h3M37 18h5M45 18h1M49 18h3M55 18h9M67 18h3M73 18h18M93 18h3M98 18h4M3 19h2M6 19h10M19 19h9M31 19h3M37 19h4M44 19h2M49 19h3M55 19h9M67 19h3M73 19h18M92 19h5M98 19h4M3 20h3M7 20h9M31 20h3M37 20h4M44 20h2M49 20h4M55 20h9M66 20h4M83 20h7M91 20h7M99 20h3M3 21h3M7 21h9M31 21h3M37 21h3M43 21h3M49 21h4M66 21h4M84 21h6M91 21h7M99 21h3M3 22h3M7 22h10M31 22h3M37 22h3M43 22h3M49 22h5M65 22h5M84 22h6M91 22h7M99 22h3M3 23h2M6 23h12M31 23h3M37 23h2M42 23h4M49 23h4M66 23h4M85 23h6M92 23h5M98 23h4M5 24h23M31 24h3M37 24h2M42 24h4M49 24h3M67 24h3M74 24h7M85 24h6M93 24h3M98 24h4M3 25h25M31 25h3M37 25h1M41 25h5M49 25h3M55 25h9M67 25h3M73 25h9M85 25h8M96 25h6M3 26h25M31 26h3M37 26h1M41 26h5M49 26h3M55 26h9M67 26h3M73 26h9M85 26h17M3 27h25M31 27h3M40 27h6M49 27h3M55 27h9M67 27h3M73 27h9M85 27h17M3 28h25M31 28h3M40 28h6M49 28h3M55 28h9M67 28h3M73 28h9M85 28h17M3 29h25M31 29h3M39 29h7M49 29h3M55 29h9M67 29h3M73 29h9M85 29h17M3 30h25M31 30h3M39 30h7M49 30h3M55 30h9M67 30h3M73 30h9M85 30h17M3 31h25M31 31h3M38 31h8M49 31h3M56 31h7M67 31h3M74 31h7M85 31h17M3 32h2M8 32h10M31 32h3M49 32h3M67 32h3M85 32h17M3 33h1M5 33h3M9 33h8M31 33h3M49 33h3M67 33h4M84 33h18M3 34h1M5 34h3M9 34h7M31 34h4M48 34h5M66 34h6M83 34h19M3 35h1M5 35h3M9 35h7M30 35h6M47 35h7M65 35h8M82 35h20M3 36h2M8 36h94M3 37h99" />
<path stroke="#d1cdd1" d="M18 8h11M36 8h11M54 8h1M17 9h13M35 9h13M53 9h1M16 10h15M34 10h15M52 10h1M16 11h3M28 11h3M34 11h3M45 11h4M16 12h3M28 12h3M34 12h3M45 12h4M16 13h3M28 13h3M34 13h3M44 13h5M16 14h3M28 14h3M34 14h3M44 14h5M16 15h3M28 15h3M34 15h3M43 15h6M16 16h3M28 16h3M34 16h3M43 16h2M46 16h3M16 17h3M28 17h3M34 17h3M42 17h3M46 17h3M16 18h3M28 18h3M34 18h3M42 18h2M46 18h3M16 19h3M28 19h3M34 19h3M41 19h3M46 19h2M16 20h15M34 20h3M41 20h2M46 20h1M17 21h14M34 21h3M40 21h3M46 21h1M18 22h13M34 22h3M40 22h2M28 23h3M34 23h3M39 23h3M28 24h3M34 24h3M39 24h2M28 25h3M34 25h3M38 25h3M28 26h3M34 26h3M38 26h2M28 27h3M34 27h6M28 28h3M34 28h5M28 29h3M34 29h5M28 30h3M34 30h4M28 31h3M34 31h4M18 32h13M34 32h3M18 33h13M35 33h2M18 34h12M56 34h2M81 34h1" />
<path stroke="#dfd7df" d="M55 8h10M72 8h13M54 9h12M71 9h13M53 10h14M70 10h13M52 11h4M63 11h4M70 11h4M52 12h3M64 12h3M70 12h3M52 13h3M64 13h3M70 13h3M52 14h3M64 14h3M70 14h3M52 15h3M64 15h3M70 15h3M52 16h3M64 16h3M70 16h3M52 17h3M64 17h3M70 17h3M52 18h3M64 18h3M70 18h3M48 19h1M52 19h3M64 19h3M70 19h3M47 20h2M53 20h2M64 20h2M70 20h13M47 21h2M54 21h11M70 21h14M46 22h3M54 22h11M70 22h14M46 23h3M53 23h13M70 23h4M81 23h4M46 24h3M52 24h3M64 24h3M70 24h3M82 24h3M46 25h3M52 25h3M64 25h3M70 25h3M82 25h3M46 26h3M52 26h3M64 26h3M70 26h3M82 26h3M46 27h3M52 27h3M64 27h3M70 27h3M82 27h3M46 28h3M52 28h3M64 28h3M70 28h3M82 28h3M46 29h3M52 29h3M64 29h3M70 29h3M82 29h3M46 30h3M52 30h3M64 30h3M70 30h3M82 30h3M46 31h3M52 31h4M63 31h4M70 31h4M81 31h4M37 32h12M52 32h15M71 32h13M17 33h1M37 33h11M53 33h13M72 33h11M16 34h2M36 34h11M54 34h2M58 34h7M73 34h8" />
<path stroke="#9f9a9f" d="M84 9h1M83 10h1M19 11h9M37 11h8M56 11h7M74 11h9M55 12h1M63 12h1M73 12h1M45 16h1M44 18h1M43 20h1M16 21h1M53 21h1M65 21h1M17 22h1M42 22h1M18 23h10M74 23h7M41 24h1M55 24h9M73 24h1M81 24h1M40 26h1M39 28h1M38 30h1M70 32h1M84 32h1M34 33h1M48 33h1M52 33h1M66 33h1M71 33h1M83 33h1M30 34h1M35 34h1M47 34h1M53 34h1M65 34h1M72 34h1M82 34h1M16 35h14M36 35h11M54 35h11M73 35h9" />
<path stroke="#8595a1" d="M6 22h1M98 22h1M5 23h1M91 23h1M97 23h1M2 24h3M91 24h2M96 24h2M93 25h3M4 35h1M8 35h1M5 36h3" />
<path stroke="#dad45e" d="M107 37h2M106 38h4M106 39h4M107 40h2" />
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
SOURCES=processor.v testbench.v memory.v registers.v alu.v decoder.v
SOURCES=processor.v testbench.v memory.v registers.v alu.v decoder.v general.v
INCLUDES=proc_state_def.v alu_header.v config.v
SYSTEM_VVP=system.vvp
BOOT_CODE=boot_code.txt

View File

@ -19,10 +19,12 @@
`include "alu_header.v"
module ALU(input [15:0]A,input [15:0]B, input oe,output reg [15:0]OUT,input [`ALU_OP_BITS-1:0]op,output wire [7:0]FLAGS,input Wbit);
module ALU(input [15:0]A,input [15:0]B,output reg [15:0]OUT,input [`ALU_OP_BITS-1:0]op,output wire [7:0]FLAGS,input Wbit);
reg C_FLAG;
wire signed [15:0]SIGNED_B;
wire signed [7:0]SIGNED_8B;
assign SIGNED_B=B;
assign SIGNED_8B=B[7:0];
assign FLAGS={(Wbit==1)?OUT[15:15]:OUT[7:7],(Wbit==1) ? (OUT[15:0]=='h0000) : (OUT[7:0]=='h00),5'b00000,C_FLAG};
@ -35,14 +37,23 @@ always @ ( * ) begin
`ALU_OP_AND: OUT=A&B;
`ALU_OP_OR: OUT=A|B;
`ALU_OP_XOR: OUT=A^B;
default:begin
OUT=0;
C_FLAG=0;
end
endcase
end else begin
case (op)
`ALU_OP_ADD: {C_FLAG,OUT[7:0]}=A[7:0]+B[7:0];
`ALU_OP_ADD_SIGNED_B: {C_FLAG,OUT[7:0]}=A[7:0]+SIGNED_8B;
`ALU_OP_SUB: {C_FLAG,OUT[7:0]}=A[7:0]-B[7:0];
`ALU_OP_AND: OUT=A&B;
`ALU_OP_OR: OUT=A|B;
`ALU_OP_XOR: OUT=A^B;
default:begin
OUT=0;
C_FLAG=0;
end
endcase
end
end

View File

@ -38,7 +38,6 @@ module decoder(
always @( CIR ) begin
ERROR=0;HALT=0;
MOD=2'b11;/*TODO:remove*/
case(CIR[15:10])
6'b000001 : begin
/* ADD, ... */
@ -56,10 +55,10 @@ always @( CIR ) begin
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b01;
out_alu1_sel=3'b011;
reg_read_port1_addr={CIR[8:8],3'b000};
reg_write_addr={CIR[8:8],3'b000};
reg_read_port1_addr={Wbit,3'b000};
reg_write_addr={Wbit,3'b000};
ALU_1OP=`ALU_OP_ADD;
if(CIR[8:8]==1)
if(Wbit==1)
next_state=`PROC_DE_LOAD_16_PARAM;
else begin
PARAM1[7:0]=CIR[7:0];
@ -75,19 +74,20 @@ always @( CIR ) begin
3'b000 : begin
/* Add Immediate word/byte to register/memory */
/* 1 0 0 0 0 0 S W | MOD 0 0 0 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */
`start_aligning_instruction
opcode_size=1;
has_operands=1;
`start_aligning_instruction
Wbit=CIR[8:8];
Sbit=CIR[9:9];
MOD=2'b11;
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b01;
out_alu1_sel={1'b0,CIR[7:6]};
reg_read_port1_addr={CIR[8:8],CIR[2:0]};
reg_write_addr={CIR[8:8],CIR[2:0]};
out_alu1_sel={1'b0,MOD};
reg_read_port1_addr={Wbit,RM};
reg_write_addr={Wbit,RM};
ALU_1OP=`ALU_OP_ADD;
next_state=`PROC_DE_LOAD_16_PARAM;
if(CIR[8:8]==1)
if(Wbit==1)
next_state=`PROC_DE_LOAD_16_PARAM;
else begin
`invalid_instruction /*do 8bit loads*/
@ -95,13 +95,14 @@ always @( CIR ) begin
end
3'b111 : begin
/* CMP - compare Immediate with register / memory */
/* 1 0 0 0 0 0 S W | MOD 0 0 0 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */
/* 1 0 0 0 0 0 S W | MOD 1 1 1 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */
opcode_size=1;
has_operands=1;
Wbit=CIR[8:8];
Sbit=CIR[9:9];
MOD=CIR[7:6];
if((Wbit==1)&&(CIR[9:9]==1))begin
RM=CIR[2:0];
if(((Wbit==1)&&(Sbit==1))||Wbit==0)begin
`start_unaligning_instruction
end else begin
`invalid_instruction;
@ -109,7 +110,7 @@ always @( CIR ) begin
if(MOD==2'b11)begin
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b01;
reg_read_port1_addr={CIR[8:8],CIR[2:0]};
reg_read_port1_addr={Wbit,RM};
out_alu1_sel=3'b100;
ALU_1OP=`ALU_OP_SUB;
next_state=`PROC_DE_LOAD_8_PARAM;
@ -127,13 +128,10 @@ always @( CIR ) begin
6'b101101:begin
/* MOV - Move Immediate byte to register */
/* 1 0 1 1 W REG | DATA | DATA if W |*/
has_operands=1;
Wbit=CIR[11:11];
opcode_size=0;
if(Wbit)
`start_unaligning_instruction
else
`start_aligning_instruction
has_operands=1;
Wbit=CIR[11:11]; /* IS 0 */
opcode_size=0;
MOD=2'b11;
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b00;
@ -147,13 +145,10 @@ always @( CIR ) begin
6'b101110,
6'b101111 : begin
/*MOV - Move Immediate word to register*/
has_operands=1;
Wbit=CIR[11:11];
opcode_size=0;
if(Wbit)
`start_unaligning_instruction
else
`start_aligning_instruction
has_operands=1;
Wbit=CIR[11:11]; /*IS 1 */
opcode_size=0;
MOD=2'b11;
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b00;
@ -179,7 +174,7 @@ always @( CIR ) begin
if(MOD==2'b11)begin
/*Reg to Reg*/
in_alu1_sel1=2'b01;
reg_read_port1_addr=CIR[2:0];
reg_read_port1_addr={Wbit,RM};
next_state=`PROC_EX_STATE_ENTRY;
end else begin
/*Mem to Reg*/
@ -194,12 +189,12 @@ always @( CIR ) begin
/*Reg to Reg*/
in_alu1_sel1=2'b01;
out_alu1_sel=3'b011;
reg_write_addr={Wbit,CIR[2:0]};
reg_write_addr={Wbit,RM};
next_state=`PROC_EX_STATE_ENTRY;
end else begin
/*Reg to Mem*/
in_alu1_sel1=2'b00;
reg_read_port1_addr=CIR[5:3];
reg_read_port1_addr={Wbit,CIR[5:3]};
out_alu1_sel={1'b0,MOD};
next_state=`PROC_DE_LOAD_REG_TO_PARAM;
end
@ -251,15 +246,15 @@ always @( CIR ) begin
RM=CIR[2:0];
in_alu1_sel1=(MOD==2'b11)? 2'b01 : 2'b00;
in_alu1_sel2=2'b00;/* number 1 */
out_alu1_sel={1'b0,MOD};
PARAM2=1;
out_alu1_sel={1'b0,MOD};
/*in case MOD=11 */
reg_read_port1_addr={1'b0,RM};
reg_write_addr={1'b0,RM};
ALU_1OP=(CIR[3:3]==1)?`ALU_OP_SUB:`ALU_OP_ADD;
if ( CIR[7:6] == 2'b11 )
if ( MOD == 2'b11 )
next_state=`PROC_EX_STATE_ENTRY;
else
next_state=`RPOC_MEMIO_READ;
@ -308,10 +303,10 @@ always @( CIR ) begin
MOD=2'b11;
in_alu1_sel1=2'b00;
in_alu1_sel2=2'b01;
reg_read_port1_addr={CIR[8:8],3'b000};
reg_read_port1_addr={Wbit,3'b000};
out_alu1_sel=3'b100;
ALU_1OP=`ALU_OP_SUB;
if(CIR[8:8]==1)
if(Wbit==1)
next_state=`PROC_DE_LOAD_16_PARAM;
else begin
PARAM1[7:0]=CIR[7:0];
@ -343,7 +338,7 @@ always @( CIR ) begin
ALU_1OP=`ALU_OP_ADD_SIGNED_B;
out_alu1_sel=3'b101;
case(CIR[11:9])
4'b000: begin
3'b000: begin
/* Jump on (not) Overflow */
if(FLAGS[11:11]==CIR[8:8])
next_state=`PROC_IF_STATE_ENTRY;
@ -351,21 +346,21 @@ always @( CIR ) begin
next_state=`PROC_EX_STATE_ENTRY;
end
end
4'b010: begin
3'b010: begin
/* Jump on (not) Zero */
if(FLAGS[6:6]==CIR[8:8])
next_state=`PROC_IF_STATE_ENTRY;
else
next_state=`PROC_EX_STATE_ENTRY;
end
4'b100: begin
3'b100: begin
/* Jump on (not) Sign */
if(FLAGS[7:7]==CIR[8:8])
next_state=`PROC_IF_STATE_ENTRY;
else
next_state=`PROC_EX_STATE_ENTRY;
end
4'b101: begin
3'b101: begin
/* Jump on (not) Parity */
if(FLAGS[2:2]==CIR[8:8])
next_state=`PROC_IF_STATE_ENTRY;
@ -424,7 +419,9 @@ always @( CIR ) begin
opcode_size=0;
`start_aligning_instruction
/* Emulate MS-DOS print routines */
if(register_file.registers[0][15:8]==8'h02)begin
$write("%s" ,register_file.registers[2][7:0]); /*TODO:Could trigger erroneously while CIR is not final*/
end
next_state=`PROC_IF_STATE_ENTRY;
end else begin
`invalid_instruction

29
system/general.v Normal file
View File

@ -0,0 +1,29 @@
/* general.v - Pieces of code that can be used by multiple other modules
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module mux4 (in1,in2,in3,in4, sel,out);
input [1:0] sel;
parameter WIDTH=16;
input [WIDTH-1:0] in1,in2,in3,in4;
output [WIDTH-1:0] out;
assign out = (sel == 'b00) ? in1 :
(sel == 'b01) ? in2 :
(sel == 'b10) ? in3 :
in4;
endmodule

View File

@ -28,10 +28,10 @@ initial begin
$readmemh(boot_code, memory);
end
assign data = !rd & !cs ? memory[address]: 'hz;
assign data = !rd & !cs ? memory[address[12:0]]: 16'hz;
always @(negedge wr) begin
memory[address]=data;
memory[address[12:0]]=data;
end
endmodule

View File

@ -21,25 +21,14 @@
`include "alu_header.v"
`include "config.v"
module mux4 (in1,in2,in3,in4, sel,out);
input [0:1] sel;
parameter WIDTH=16;
input [WIDTH-1:0] in1,in2,in3,in4;
output [WIDTH-1:0] out;
assign out = (sel == 'b00) ? in1 :
(sel == 'b01) ? in2 :
(sel == 'b10) ? in3 :
in4;
endmodule
module processor ( input clock, input reset, output reg [19:0] external_address_bus, inout [15:0] external_data_bus,output reg read, output reg write, output reg HALT,output reg ERROR);
/*if we don't read, output the register to have the bus stable by the write falling edge*/
reg [15:0] data_bus_output_register;
assign external_data_bus=read?data_bus_output_register:'hz;
assign external_data_bus=read?data_bus_output_register:16'hz;
/*** Global Definitions ***/
// State
reg [`PROC_STATE_BITS-1:0] state;
/* Decoder */
@ -70,27 +59,7 @@ reg one_byte_instruction;
reg unaligned_access;
reg [15:0]FLAGS;
/* . . . . O D I T S Z . A . P . C */
// C - Carry flag : carry out or borrow into the high order bit (8bit/16bit)
//
// P - Parity flag : is set if result has even parity
//
// A - Auxiliary flag : carry out from the low nibble to the high nibble or
// an equiv borrow. Used by decimal arithmetic instructions
//
// Z - Zero flag : Set when result of Operation is zero
//
// S - Sign flag : set if the high order bit of the result is 1. aka the sign
// of the result
//
// T - Trap flag : Set the CPU into single step mode where it generates an
// interrupt after each instruction
//
// I - Interrupt flag : 0: interrupts are masked
//
// D - Direction flag : 1: string instructions decrement 0: they increment
//
// O - Overflow flag : set on arithmetic overflow
reg [15:0] BYTE_WRITE_TEMP_REG;//we read 16bits here if we want to change just 8 and leave the rest
@ -103,7 +72,6 @@ always @(negedge reset) begin
HALT=0;
reg_write_we=1;
unaligned_access=0;
ALU_1OE=1;
@(posedge reset)
@(negedge clock);
state=`PROC_IF_STATE_ENTRY;
@ -156,9 +124,8 @@ wire [15:0] ALU_1A;
wire [15:0] ALU_1B;
wire [15:0] ALU_1O;
reg [`ALU_OP_BITS-1:0]ALU_1OP;
reg ALU_1OE;
wire [7:0] ALU_1FLAGS;
ALU ALU1(ALU_1A,ALU_1B,ALU_1OE,ALU_1O,ALU_1OP,ALU_1FLAGS,Wbit);
ALU ALU1(ALU_1A,ALU_1B,ALU_1O,ALU_1OP,ALU_1FLAGS,Wbit);
/*** Processor stages ***/
`define invalid_instruction state=`PROC_IF_STATE_ENTRY;ERROR=1;
@ -183,7 +150,6 @@ always @(negedge clock) begin
`PROC_IF_STATE_EXTRA_FETCH:begin
CIR[7:0] <= external_data_bus[15:8];
state=`PROC_DE_STATE_ENTRY;
ALU_1OE=0;
end
`PROC_EX_STATE_EXIT:begin
unaligned_access=unaligning_instruction^unaligned_access;
@ -234,7 +200,7 @@ always @(negedge clock) begin
state=`PROC_IF_STATE_ENTRY;
end
3'b101:begin
ProgCount=ALU_1O[15:1];
ProgCount={5'b00000,ALU_1O[15:1]};
unaligned_access=ALU_1O[0:0];
state=`PROC_IF_STATE_ENTRY;
end
@ -251,7 +217,7 @@ always @(negedge clock) begin
state=`PROC_DE_LOAD_16_EXTRA_FETCH;
end
`PROC_MEMIO_READ_SETADDR:begin
external_address_bus = {1'b0,reg_read_port1_data[15:1]};
external_address_bus = {5'b00000,reg_read_port1_data[15:1]};
state=reg_read_port1_data[0:0]?`PROC_MEMIO_GET_UNALIGNED_DATA:`PROC_MEMIO_GET_ALIGNED_DATA;
end
`PROC_MEMIO_PUT_BYTE:begin
@ -292,6 +258,8 @@ always @(negedge clock) begin
end
state=`PROC_EX_STATE_ENTRY;
end
default:begin
end
endcase
end
@ -309,21 +277,20 @@ always @(posedge clock) begin
if(ERROR!=1)
$display("Fetched instruction at %04x",{ProgCount[18:0],unaligned_access});
`endif
external_address_bus <= ProgCount;
read <= 0;
write <= 1;
external_address_bus = ProgCount;
read = 0;
write = 1;
reg_write_we=1;
ALU_1OE=1;
state=`PROC_IF_WRITE_CIR;
reg_write_in_sel=2'b00;
end
`PROC_IF_STATE_EXTRA_FETCH_SET:begin
ProgCount=ProgCount+1;
external_address_bus <= ProgCount;
external_address_bus = ProgCount;
state=`PROC_IF_STATE_EXTRA_FETCH;
end
`PROC_DE_STATE_ENTRY:begin
/* IF we are unaligned, the address bus contains the
/* If we are unaligned, the address bus contains the
* ProgCount and points to the second word containing
* the nest unread byte in extenral_data_bus[7:0]. If
* we are aligned the address bus points to the first
@ -332,7 +299,7 @@ always @(posedge clock) begin
* address so update it now so that whatever the case
* external_data_bus contains at leat some unkown data */
one_byte_instruction=(!has_operands)&&(!opcode_size);
external_address_bus <= ProgCount;
external_address_bus = ProgCount;
state=next_state;
PARAM1=DE_PARAM1;
PARAM2=DE_PARAM2;
@ -441,7 +408,7 @@ always @(posedge clock) begin
end
`PROC_MEMIO_GET_ALIGNED_DATA:begin
PARAM1=(Wbit==1)? external_data_bus : {8'b00000000,external_data_bus[15:8]} ;
PARAM1=(Wbit==1)? {external_data_bus[7:0],external_data_bus[15:8]} : {8'b00000000,external_data_bus[15:8]} ;
state=`PROC_EX_STATE_ENTRY;
end
`PROC_MEMIO_GET_UNALIGNED_DATA:begin
@ -461,7 +428,7 @@ always @(posedge clock) begin
`ifdef DEBUG_MEMORY_WRITES
$display("Writing at %04x , %04x",reg_read_port1_data,ALU_1O);
`endif
external_address_bus = {1'b0,reg_read_port1_data[15:1]};
external_address_bus = {5'b00000,reg_read_port1_data[15:1]};
state = (Wbit==0) ? `PROC_MEMIO_PUT_BYTE : (reg_read_port1_data[0:0]?`PROC_MEMIO_PUT_UNALIGNED_DATA:`PROC_MEMIO_PUT_ALIGNED_DATA) ;
end
`PROC_MEMIO_PUT_BYTE_STOP_READ:begin
@ -492,6 +459,8 @@ always @(posedge clock) begin
PARAM1[15:8]=external_data_bus[15:8];
state=`PROC_EX_STATE_ENTRY;
end
default:begin
end
endcase
end

View File

@ -36,18 +36,21 @@ assign read_port1_data = ( read_port1_addr[3:3] ? registers[read_port1_addr[2:0]
string debug_name;
`endif
wire write_Wbit;
assign write_Wbit=write_port1_addr[3:3];
always @(negedge write_port1_we) begin
if(write_port1_addr[3:3]==1)begin
if(write_Wbit==1)begin
/* Word : AX,CX,DX,BX,SP,BP,SI,DI */
registers[write_port1_addr[2:0]]=write_port1_data;
end else begin
/* Byte : AL,CL,DL,BL,AX,CX,DX,BX */
if(write_port1_addr[2:2]==1)begin
/* Byte */
registers[write_port1_addr[2:0]][15:8]=write_port1_data[7:0];
registers[write_port1_addr[1:0]][15:8]=write_port1_data[7:0];
end else begin
/* Byte */
registers[write_port1_addr[2:0]][7:0]=write_port1_data[7:0];
registers[write_port1_addr[1:0]][7:0]=write_port1_data[7:0];
end
end
@ -67,8 +70,11 @@ always @(negedge write_port1_we) begin
2'b11: debug_name="bx";
endcase
end
if (write_Wbit)begin
$display("register %%%s update to $0x%04x",debug_name,registers[write_port1_addr[2:0]]);
end else begin
$display("register %%%s update to $0x%04x",debug_name,registers[write_port1_addr[1:0]]);
end
`endif
end
endmodule

View File

@ -46,7 +46,7 @@ initial begin
$dumpvars(0,p,u1);
end
reset = 0;
clk_enable <= 1;
clk_enable = 1;
#($random%500)
#(`CPU_SPEED)
@ -100,8 +100,8 @@ end
// Initialise variables to zero
initial begin
clk <= 0;
start_clk <= 0;
clk = 0;
start_clk = 0;
end
// When clock is enabled, delay driving the clock to one in order