diff --git a/8086_documentation.md b/8086_documentation.md
index 9901a01..02e4d70 100644
--- a/8086_documentation.md
+++ b/8086_documentation.md
@@ -4,41 +4,32 @@ Instructions vary from 1 to 6 bytes.
### Instructions format
| 6bit | 1bit | 1bit | 2bit | 3bit | 3bit |
| ---------------- | --------- | ---- | ---- | ---- | ---- |
-| Opcode | D bit | W bit | MOD | REG | R/M |
+| 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 2’s 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 2’s 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
+| S | W | Operation |
+| --- | --- | ----------------------------------------------------- |
+| 0 | 0 | 8bit operation |
+| 0 | 1 | 16bit operation with 16bit immediate operand |
+| 1 | 0 | invalid? |
+| 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
diff --git a/README.md b/README.md
index 8880349..44e3c03 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
-# 9086
+
+
+#
A CPU that aims to be binary compatible with the 8086 and with as many optimisations as possible
diff --git a/boot_code/Makefile b/boot_code/Makefile
index 15dc791..5083d1f 100644
--- a/boot_code/Makefile
+++ b/boot_code/Makefile
@@ -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:
diff --git a/boot_code/brainfuck.asm b/boot_code/brainfuck.asm
index 6dba1b2..6b14919 100644
--- a/boot_code/brainfuck.asm
+++ b/boot_code/brainfuck.asm
@@ -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 .
+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 '+++++++.---.--.<<.>---------------------.>+++++.-----------------.++++++++.+++++.--------.+++++++++++++++.---------------'
diff --git a/boot_code/brainfuck_interpreter_v0.asm b/boot_code/brainfuck_interpreter_v0.asm
new file mode 100644
index 0000000..20d5fb7
--- /dev/null
+++ b/boot_code/brainfuck_interpreter_v0.asm
@@ -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 .
+
+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
diff --git a/boot_code/brainfuck_mandelbrot.asm b/boot_code/brainfuck_mandelbrot.asm
index ae39f2f..7b82c94 100644
--- a/boot_code/brainfuck_mandelbrot.asm
+++ b/boot_code/brainfuck_mandelbrot.asm
@@ -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 .
+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 '>+<<<<<<<<<<<<<<<<<[<<<<<<<<<]>>>[-]+[>>>>>>[>>>>>>>[-]>>]<<<<<<<<<[<<<<<<<<<]>>'
diff --git a/readme_files/9086_design1.ase b/readme_files/9086_design1.ase
new file mode 100644
index 0000000..adc0d4e
Binary files /dev/null and b/readme_files/9086_design1.ase differ
diff --git a/readme_files/9086_design1.svg b/readme_files/9086_design1.svg
new file mode 100644
index 0000000..278c7a9
--- /dev/null
+++ b/readme_files/9086_design1.svg
@@ -0,0 +1,12 @@
+
diff --git a/system/Makefile b/system/Makefile
index 0074b11..d840247 100644
--- a/system/Makefile
+++ b/system/Makefile
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-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
diff --git a/system/alu.v b/system/alu.v
index e2af38e..c4a4bdb 100644
--- a/system/alu.v
+++ b/system/alu.v
@@ -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
diff --git a/system/decoder.v b/system/decoder.v
index 56d29af..6029cfb 100644
--- a/system/decoder.v
+++ b/system/decoder.v
@@ -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 |*/
+ `start_aligning_instruction
has_operands=1;
- Wbit=CIR[11:11];
+ Wbit=CIR[11:11]; /* IS 0 */
opcode_size=0;
- if(Wbit)
- `start_unaligning_instruction
- else
- `start_aligning_instruction
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*/
+ `start_unaligning_instruction
has_operands=1;
- Wbit=CIR[11:11];
+ Wbit=CIR[11:11]; /*IS 1 */
opcode_size=0;
- if(Wbit)
- `start_unaligning_instruction
- else
- `start_aligning_instruction
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 */
- $write("%s" ,register_file.registers[2][7:0]); /*TODO:Could trigger erroneously while CIR is not final*/
+ 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
diff --git a/system/general.v b/system/general.v
new file mode 100644
index 0000000..c96ebd6
--- /dev/null
+++ b/system/general.v
@@ -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 . */
+
+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
diff --git a/system/memory.v b/system/memory.v
index e3d1381..5ab1c0b 100644
--- a/system/memory.v
+++ b/system/memory.v
@@ -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
diff --git a/system/processor.v b/system/processor.v
index 082f2ac..9e33dcb 100644
--- a/system/processor.v
+++ b/system/processor.v
@@ -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
diff --git a/system/registers.v b/system/registers.v
index c5d0139..f75d8d6 100644
--- a/system/registers.v
+++ b/system/registers.v
@@ -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
-
- $display("register %%%s update to $0x%04x",debug_name,registers[write_port1_addr[2:0]]);
+ 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
diff --git a/system/testbench.v b/system/testbench.v
index 74ce7c0..383912c 100644
--- a/system/testbench.v
+++ b/system/testbench.v
@@ -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