From fd4a9b54420953ddd5c021d81453e564018cf35f Mon Sep 17 00:00:00 2001 From: "(Tim) Efthimis Kritikos" Date: Sun, 19 Feb 2023 00:20:53 +0000 Subject: [PATCH] Fixed register addressing bug, mem read endianness, cleaned up code and added a provisional project logo --- 8086_documentation.md | 61 +++++++----- README.md | 4 +- boot_code/Makefile | 5 +- boot_code/brainfuck.asm | 119 +---------------------- boot_code/brainfuck_interpreter_v0.asm | 129 +++++++++++++++++++++++++ boot_code/brainfuck_mandelbrot.asm | 123 +---------------------- readme_files/9086_design1.ase | Bin 0 -> 2177 bytes readme_files/9086_design1.svg | 12 +++ system/Makefile | 2 +- system/alu.v | 13 ++- system/decoder.v | 65 ++++++------- system/general.v | 29 ++++++ system/memory.v | 4 +- system/processor.v | 67 ++++--------- system/registers.v | 16 ++- system/testbench.v | 6 +- 16 files changed, 297 insertions(+), 358 deletions(-) create mode 100644 boot_code/brainfuck_interpreter_v0.asm create mode 100644 readme_files/9086_design1.ase create mode 100644 readme_files/9086_design1.svg create mode 100644 system/general.v 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 +9086 logo + +# 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 0000000000000000000000000000000000000000..adc0d4edb19c977d3e902af8438f7163644c8e47 GIT binary patch literal 2177 zcmcJNc~n!^7RE0kGFX9%)F?W5TEQFwA>V`n|3I-< zg7vR@93;1j{Mijo0geFp01n6i3zz^1XaEH`00Ic0J?IS@Z}i<1xTq0ad~;)iDFp?4 zor9D8`~zX1&5MijYM)I>LZr|TAA%QAtL4jnreh1i+fd5$_{8THtOA)lGSNgK?N92=x zI$hmDR1e#s#v&ir-mu=OooaEzbhT5*qq;j8WtklRj$FF~MMJgXA61sF3-aA(`uR_F zeP_7AIKj(B&T&pGwVSQ^vjSp|#8-c~V*uIcuk13w({ym35;aea# zz6f#cMQZ&9aYNh$rKPNke2X2!qL?y<%8P{I<4+v=VU9{RfxepMUbgLZ(qq-kKmc(o1BGFz@eKFe|IS5r5Lp((Qo3p&Ye>*?<$s zqH_B?eN$`sGQ3uz1}EF4NceQI&S_4In#W-2G1@}4S}$0$STD;5nknlIBTvp|WrpFW z4Q8s>n^(T&r7xOXr;)rF1F})|7tT>*Z>>~6mMERl9j{8Wx){nCnrT}RY-ds8mFri< zLhclpzZAQiN}TaRb~nFDi#1{6)C8CHBQnWWOXj&$EGCBAhs8iw34;FS^#`f3{0T`Y z_Hlt*Ch~=_YIfbty;M>_W?RApWR<6?AsFtA(QmHG!$GQX=yK1}*1qx}2AWhywB)B^ zF#-9$Hx~`E+M=@Ltc>=sEr2@`@GX!yB=HxQyr8|Jc{lwm4M9@S54WP;tR2MO`EOs* z!@n#!Rn+igz4V67;?NfGY}!nO5TXWo_8T^n%=a{8U}qtZj{DeInT-9<<#)o=F>>>& zT}4iWWe+>f5zFQIX!KHTe1jHx@~jT8rnAPqUMAiGVMcDW{1-WpnX7WIu1){_Jd&7i zTF#5sIn`0!(q2B?8Alt%lRPI1kx1Ivpm4h3`>x};;gp}u`6oLLhOY&OC<{*uKMbg6 z1!<9nziT~35^xf)I7Cc*l0t{qU$PL)VHJIG`s`Ku`}I{;&iQ~|-z#H;mW{$pgnWjj)20MMmV<%OvQ@CpBDh@hF1f`jZ~* zN88%%6Ep2%<*B*v-L}n8x_rUhi^lfnS1nfj#Lm9$TvCZP+GnV8I$<(0+Amf+^c!>S z2wh(Dl*PPLiNf5`r^g~sqDomZiPx|RlfjX;?+Eb`BlW=?s{7zq3e@Bl?*hc&zN})| z$sSWorKFw5&1iYes}9do4hqlh^oswz;@*LtrO8{_?75V7o>I>kwJ{OK;o(tOgSq6< zytJNYHXSC7$0n)$Kj-jO33nImVr!Llm$X-&(5{WhX4jWitIRpJ7m`X2&$!ZbHSs8# zHTQL5m6XDT06RgO!O>7dT&{zL0w*dtA}6Ra*ArIGpI%G9#=ViY6mm$@rrSVUVG6C9 z(T-`L-MUsiNNrQkO?cqU9&?^JJy5|ldd!|rnT%jbqWS#5LA>Uwl2N*4M%G)mshwz} z#VC|qAfwp0&QT??vL<}5i6dsh1j|PycJ6)TSdwslYMdd)%}gz$Y>Yz!lKaOvU|<}h zw@qc6jz}Gg5!T(Gy_T+>D$zx?SFj7b`1M=nmccU^9w#nzAON@OU26a%^8+rahNY9ZGY0NRtU49Y?zDD;``@m=nCvJ<59*lyBae`pPK6~Xkp8f!`FTH$DInI sD9RS5gdlvXTNN9gD`YnP;uw_@qlqr^b;8~BN#`v8HW34v?#bN#2W9kV+5i9m literal 0 HcmV?d00001 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