From da51dd6da786ec51b0521be8c4a828d227f36a12 Mon Sep 17 00:00:00 2001 From: "(Tim) Efthimis Kritikos" Date: Sun, 7 May 2023 13:34:15 +0100 Subject: [PATCH] First draft of a bus interface unit in an effort to make the CPU pipelined. Currently supports code prefetching --- gtkwave_savefile.gtkw | 57 +++-- system/Makefile | 4 +- system/biu.v | 305 +++++++++++++++++++++++++++ system/decoder.v | 29 ++- system/error_header.v | 4 + system/proc_state_def.v | 45 ++-- system/processor.v | 457 +++++++++++++++++----------------------- system/system.v | 37 +++- system/testbench.v | 2 +- 9 files changed, 603 insertions(+), 337 deletions(-) create mode 100644 system/biu.v create mode 100644 system/error_header.v diff --git a/gtkwave_savefile.gtkw b/gtkwave_savefile.gtkw index 48fe1cc..c347388 100644 --- a/gtkwave_savefile.gtkw +++ b/gtkwave_savefile.gtkw @@ -1,43 +1,62 @@ [*] [*] GTKWave Analyzer v3.3.111 (w)1999-2020 BSI -[*] Thu Mar 9 04:20:33 2023 +[*] Sun May 7 11:35:53 2023 [*] [dumpfile] "/home/user/9086/system/boot_code.fst" -[dumpfile_mtime] "Thu Mar 9 04:18:18 2023" -[dumpfile_size] 8510 +[dumpfile_mtime] "Sun May 7 11:35:19 2023" +[dumpfile_size] 13013 [savefile] "/home/user/9086/gtkwave_savefile.gtkw" -[timestart] 198700000000 -[size] 1236 1017 +[timestart] 500000000 +[size] 1524 993 [pos] -1 -1 -*-34.595051 280500000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-36.395050 127070000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] TOP. [treeopen] TOP.system. -[sst_width] 221 +[treeopen] TOP.system.p. +[treeopen] TOP.system.p.BIU. +[sst_width] 263 [signals_width] 293 [sst_expanded] 1 [sst_vpaned_height] 312 @28 TOP.system.clock TOP.system.reset -TOP.system.p.state[5:0] @22 -TOP.system.p.ucode_seq_addr[4:0] TOP.system.address_bus[19:0] TOP.system.data_bus[15:0] -TOP.system.p.CIR[15:0] -TOP.system.p.PARAM1[15:0] -TOP.system.p.PARAM2[15:0] +TOP.system.p.BIU.biu_state[3:0] @28 TOP.system.p.read TOP.system.p.write -@29 TOP.system.IOMEM -@22 -TOP.system.p.ALU_1A[15:0] -TOP.system.p.ALU_1B[15:0] -TOP.system.p.ALU_1O[15:0] -@28 -TOP.system.p.ERROR +TOP.system.p.ERROR[2:0] TOP.system.p.HALT +@29 +TOP.system.p.state[3:0] +@22 +TOP.system.p.BIU.INSTRUCTION[31:0] +@28 +TOP.system.p.BIU.VALID_INSTRUCTION +TOP.system.p.BIU.NEXT_POSITION[1:0] +@22 +TOP.system.p.BIU.FIFO_end[3:0] +TOP.system.p.BIU.FIFO_start[3:0] +TOP.system.p.BIU.INPUT_FIFO[0][7:0] +TOP.system.p.BIU.INPUT_FIFO[1][7:0] +TOP.system.p.BIU.INPUT_FIFO[2][7:0] +TOP.system.p.BIU.INPUT_FIFO[3][7:0] +TOP.system.p.BIU.INPUT_FIFO[4][7:0] +TOP.system.p.BIU.INPUT_FIFO[5][7:0] +TOP.system.p.BIU.INPUT_FIFO[6][7:0] +TOP.system.p.BIU.INPUT_FIFO[7][7:0] +TOP.system.p.BIU.INPUT_FIFO[8][7:0] +TOP.system.p.BIU.INPUT_FIFO[9][7:0] +TOP.system.p.BIU.INPUT_FIFO[10][7:0] +TOP.system.p.BIU.INPUT_FIFO[11][7:0] +TOP.system.p.BIU.INPUT_FIFO[12][7:0] +TOP.system.p.BIU.INPUT_FIFO[13][7:0] +TOP.system.p.BIU.INPUT_FIFO[14][7:0] +TOP.system.p.BIU.INPUT_FIFO[15][7:0] +TOP.system.p.ucode_seq_addr[4:0] [pattern_trace] 1 [pattern_trace] 0 diff --git a/system/Makefile b/system/Makefile index cdb7321..33d1e2a 100644 --- a/system/Makefile +++ b/system/Makefile @@ -16,7 +16,7 @@ # along with this program. If not, see . # TOP_LEVEL_SOURCE=system.v -SOURCES=processor.v memory.v registers.v alu.v decoder.v general.v +SOURCES=processor.v memory.v registers.v alu.v decoder.v general.v biu.v EVENT_SIM_TESTBENCH=testbench.v VERILATOR_TESTBENCH=testbench.cpp INCLUDES=proc_state_def.v alu_header.v config.v ucode_header.v @@ -41,7 +41,7 @@ VERILATOR_OPTS += -Wall --Wno-DECLFILENAME -Wno-SYNCASYNCNET -Wno-MULTIDRIVEN #optimisation options VERILATOR_OPTS += -x-assign fast --x-initial fast #For testing use: -#VERILATOR_OPTS=-x-assign unique --x-initial unique +#VERILATOR_OPTS += -x-assign unique --x-initial unique # COMPILING ${SYSTEM_VVP} : ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES} ${EVENT_SIM_TESTBENCH} diff --git a/system/biu.v b/system/biu.v new file mode 100644 index 0000000..e4f4939 --- /dev/null +++ b/system/biu.v @@ -0,0 +1,305 @@ +/* processor.v - implementation of the 9086 bus interface unit. The logic that + controls all external bus functions + + 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 . */ + +//IOMEM: 1=IO 0=MEM + +`define BIU_HALT 4'b0000 +`define BIU_NEXT_ACTION 4'b0001 +`define BIU_READ 4'b0010 +`define BIU_RESET 4'b0011 + +`define BIU_PUT_BYTE 4'b0100 +`define BIU_PUT_UNALIGNED_16BIT_DATA 4'b0101 +`define BIU_PUT_ALIGNED_16BIT_DATA 4'b0110 +`define BIU_PUT_UNALIGNED_PREP_NEXT 4'b0111 +`define BIU_PUT_UNALIGNED_PREP_NEXT2 4'b1000 +`define BIU_WRITE_EXIT 4'b1001 +`define BIU_WRITE_RELEASE 4'b1010 + +`define BIU_GET_ALIGNED_DATA 4'b1011 +`define BIU_GET_UNALIGNED_DATA 4'b1100 +`define BIU_GET_SECOND_BYTE 4'b1101 +`define BIU_GET_SECOND_BYTE1 4'b1110 + +module BIU ( +/*outside world*/ 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 BHE,output reg IOMEM, +/* internal */ output reg [31:0] INSTRUCTION, output reg VALID_INSTRUCTION, output reg [15:0] INSTRUCTION_LOCATION, input [1:0] NEXT_POSITION, +/* */ input[15:0] ADDRESS_INPUT, inout [15:0] DATA, input write_request, input read_request, input Wbit, output reg VALID_DATA, input MEM_OR_IO + ); + +reg [15:0] data_bus_output_register; +assign external_data_bus=read?data_bus_output_register:16'hz; + +reg [15:0] DATA_OUT; +reg DATA_DIR; +assign DATA=DATA_DIR ? 16'hz:DATA_OUT; + +reg [7:0] INPUT_FIFO [15:0]; //8bit fifo memory with 4bit address bus + +reg [3:0] FIFO_start; /*inclusive*/ +reg [3:0] FIFO_end; /*exclusive*/ + +reg [3:0] biu_state; + +always @(negedge reset) begin + biu_state <= `BIU_HALT; +end + +always @(posedge reset) begin + biu_state <= `BIU_RESET; +end + +reg jump_req; + +reg func; +reg [19:0]INSTRUCTION_ADDRESS; +reg [19:0]DATA_ADDRESS; +assign external_address_bus= func? INSTRUCTION_ADDRESS : DATA_ADDRESS ; + +/* Read into the FIFO */ +always @(posedge clock) begin + if ( jump_req ) begin + /* verilator lint_off BLKSEQ */ + FIFO_start = 4'b0; + /* verilator lint_on BLKSEQ */ + FIFO_end <= 4'b0; + INSTRUCTION_ADDRESS <= { 4'b0 , ADDRESS_INPUT-16'd1 }; + INSTRUCTION_LOCATION <= ADDRESS_INPUT; + func <= 1; + jump_req <= 0; + if (biu_state==`BIU_READ) + biu_state <= `BIU_NEXT_ACTION; + end else begin + case(biu_state) + `BIU_HALT: begin + end + `BIU_NEXT_ACTION: begin /* decide if we can read, if we are full or if we need to do something else */ + if (write_request) begin + func<=0; + DATA_ADDRESS <= { 4'b0 , ADDRESS_INPUT }; + DATA_DIR <= 1 ; + VALID_INSTRUCTION <= 0; + IOMEM <= MEM_OR_IO; + biu_state <= (Wbit==0) ? `BIU_PUT_BYTE : (ADDRESS_INPUT[0:0]?`BIU_PUT_UNALIGNED_16BIT_DATA:`BIU_PUT_ALIGNED_16BIT_DATA) ; + end else if ( read_request ) begin + func<=0; + DATA_ADDRESS <= { 4'b0 , ADDRESS_INPUT }; + VALID_INSTRUCTION <= 0; + DATA_DIR <= 0; + read <=0; + biu_state <= (ADDRESS_INPUT[0:0])?`BIU_GET_UNALIGNED_DATA:`BIU_GET_ALIGNED_DATA; + end else begin + if((FIFO_end-FIFO_start)>4'b0011)begin + VALID_INSTRUCTION <= 1; + INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start]; + INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+4'd1]; + INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+4'd2]; + INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+4'd3]; + end + if ( FIFO_end[3:0]+4'b0001 != FIFO_start[3:0] ) begin + func<=1; + biu_state <= `BIU_READ; + INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+1; + write <= 1; + read <= 0; + IOMEM <= 0; + BHE <= 0; + end else begin + biu_state <= `BIU_NEXT_ACTION; + end + end + end + + /*************** INSTRUCTION FIFO READ ***************/ + `BIU_READ: begin + /* verilator lint_off BLKSEQ */ + if(INSTRUCTION_ADDRESS[0:0]==0)begin + INPUT_FIFO[FIFO_end] = external_data_bus[7:0]; + end else begin + INPUT_FIFO[FIFO_end] = external_data_bus[15:8]; + end + /* verilator lint_on BLKSEQ */ + FIFO_end <= FIFO_end+1; + biu_state <= `BIU_NEXT_ACTION; + read<=1; + end + + + /*************** DATA WRITE ***************/ + //TODO TODO TODO flush fifo, self modifying code + `BIU_PUT_UNALIGNED_16BIT_DATA:begin + BHE <= 0; + data_bus_output_register <= {DATA[7:0],DATA[15:8]}; + biu_state <= `BIU_PUT_UNALIGNED_PREP_NEXT; + end + `BIU_PUT_UNALIGNED_PREP_NEXT:begin + write <= 0; + biu_state <= `BIU_PUT_UNALIGNED_PREP_NEXT2; + end + `BIU_PUT_UNALIGNED_PREP_NEXT2:begin + write <= 1; + DATA_ADDRESS <= DATA_ADDRESS+1; + BHE <= 1; + biu_state <= `BIU_WRITE_EXIT; + end + `BIU_PUT_ALIGNED_16BIT_DATA:begin + data_bus_output_register <= {DATA[15:8],DATA[7:0]}; + biu_state <= `BIU_WRITE_EXIT; + end + `BIU_PUT_BYTE:begin + biu_state <= `BIU_WRITE_EXIT; + if(ADDRESS_INPUT[0:0]==0) begin + BHE <= 1; + data_bus_output_register <= {8'b0,DATA[7:0]}; + end else begin + BHE <= 0; + data_bus_output_register <= {DATA[7:0],8'b0}; + end + end + `BIU_WRITE_EXIT:begin + write <= 0; + biu_state <= `BIU_WRITE_RELEASE; + end + `BIU_WRITE_RELEASE:begin + write <= 1; + biu_state <= `BIU_NEXT_ACTION; + end + + + /*************** DATA READ ***************/ + `define finished_read \ + DATA_DIR <= 0; \ + VALID_DATA <= 1;\ + if ( read_request == 0 ) begin \ + biu_state <= `BIU_NEXT_ACTION;\ + VALID_DATA <= 0;\ + end + `BIU_GET_ALIGNED_DATA:begin + DATA_OUT <= (Wbit==1)? external_data_bus : {8'b0,external_data_bus[7:0]} ; + read <=1; + `finished_read + end + `BIU_GET_UNALIGNED_DATA:begin + DATA_OUT[7:0] <= external_data_bus[15:8]; + read <=1; + if(Wbit==1) begin + biu_state <= `BIU_GET_SECOND_BYTE; + end else begin + `finished_read + end + end + `BIU_GET_SECOND_BYTE:begin + DATA_ADDRESS <= DATA_ADDRESS+1; + biu_state <= `BIU_GET_SECOND_BYTE1; + read <=0; + end + `BIU_GET_SECOND_BYTE1:begin + DATA_OUT[15:8] <= external_data_bus[7:0]; + `finished_read + read <=1; + end + + /*************** HOUSE KEEPING ***************/ + `BIU_RESET: begin + /* verilator lint_off BLKSEQ */ + FIFO_start = 4'b0; + /* verilator lint_on BLKSEQ */ + FIFO_end <= 4'b0; + biu_state <= `BIU_NEXT_ACTION; + INSTRUCTION_ADDRESS <= 20'h0FFEF; + INSTRUCTION_LOCATION <= 16'hFFF0; + VALID_INSTRUCTION <= 0; + VALID_DATA <= 0; + DATA_DIR <= 0; + end + default: begin + biu_state <= `BIU_NEXT_ACTION;/*Should be unreachable*/ + end + endcase + end +end + +wire [2:0] Isize; +InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},Isize); + +always @( NEXT_POSITION ) begin + case(NEXT_POSITION) + 2'b00:begin end /* no action */ + 2'b01:begin /* Next instruction */ + /* verilator lint_off BLKSEQ */ + FIFO_start = FIFO_start + {1'b0,Isize}; + INSTRUCTION_LOCATION <= INSTRUCTION_LOCATION + {12'b0,Isize};; + /* verilator lint_on BLKSEQ */ + if((FIFO_end-FIFO_start)>4'b0011)begin + VALID_INSTRUCTION <= 1; + INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start]; + INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+4'd1]; + INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+4'd2]; + INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+4'd3]; + end else begin + VALID_INSTRUCTION <= 0; + end + + end + 2'b10:begin /* Jump to specific location based on register */ + jump_req <= 1; + VALID_INSTRUCTION <= 0; + end + 2'b11:begin /* Jump to absolute location */ + end + endcase +end + +endmodule + +/* Pre-Decode the instruction size */ +/* IN: {CIR[15:8],CIR[5:3]} */ +/* OUT: number in bytes */ +module InstrSize ( input [10:0] IN, output reg [2:0] VERDICT ); + always @( IN ) begin + casez(IN) + 11'b0000_010?_??? : VERDICT <= 3'd2+{2'b0,IN[3:3]}; /* ADD - Add Immediate word/byte to accumulator */ + 11'b1000_00??_101 : VERDICT <= 3'd3+{2'b0,(IN[4:3]==2'b01)}; /* SUB - Subtract immediate word/byte from register/memory */ + 11'b1000_00??_000 : VERDICT <= 3'd3+{2'b0,(IN[4:3]==2'b01)}; /* ADD - Add Immediate word/byte to register/memory */ + 11'b1000_00??_111 : VERDICT <= 3'd3+{2'b0,(IN[4:3]==2'b01)}; /* CMP - compare Immediate with register / memory */ + 11'b1011_????_??? : VERDICT <= 3'd2+{2'b0,IN[6:6]}; /* MOV - Move Immediate byte to register */ + 11'b1000_10??_??? : VERDICT <= 3'd2; /* MOV - Reg/Mem to/from register */ + 11'b0100_????_??? : VERDICT <= 3'd1; /* DEC - Decrement Register | INC - Increment Register */ + 11'b1111_111?_00? : VERDICT <= 3'd2; /* INC - Register/Memory | DEC - Register/Memory */ + 11'b1111_0100_??? : VERDICT <= 3'd1; /* HLT - Halt */ + 11'b0011_110?_??? : VERDICT <= 3'd2+{2'b0,IN[3:3]}; /* CMP - Compare Immediate with accumulator */ + 11'b0111_????_??? : VERDICT <= 3'd2; /* Conditional relative jumps ( JE/JZ, JS/JNS ... ) */ + 11'b1110_1011_??? : VERDICT <= 3'd2; /* JMP - Unconditional jump direct within segment (short) */ + 11'b1110_1000_??? : VERDICT <= 3'd3; /* CALL - Direct call within segment */ + 11'b1100_0011_??? : VERDICT <= 3'd1; /* RET - Return from call within segment */ + 11'b1010_101?_??? : VERDICT <= 3'd1; /* STOS - Write byte/word to [DI] and increment accordingly */ + 11'b0101_0???_??? : VERDICT <= 3'd1; /* PUSH - SP-=2; [SP]=REG */ + 11'b1111_011?_000 : VERDICT <= 3'd3+{2'b0,IN[3:3]}; /* TEST - Bitwise AND affecting only flags */ + 11'b0101_1???_??? : VERDICT <= 3'd1; /* POP - REG=[SP]; SP+=2 */ + 11'b1111_1111_100 : VERDICT <= 3'd2; /* JMP - Unconditional indirect within segment jump */ + 11'b1100_011?_000 : VERDICT <= 3'd3+{2'b0,IN[3:3]}; /* MOV - Move immediate to register/memory */ + 11'b1100_1101_??? : VERDICT <= 3'd2; /* INT - execute interrupt handler */ + 11'b1110_011?_??? : VERDICT <= 3'd2; /* OUT - write AL or AX to a defined output port */ + 11'b1100_1111_??? : VERDICT <= 3'd1; /* IRET - Return from interrupt */ + default:begin end + endcase + end +endmodule diff --git a/system/decoder.v b/system/decoder.v index 33d1dc0..a8c620a 100644 --- a/system/decoder.v +++ b/system/decoder.v @@ -20,6 +20,7 @@ `include "proc_state_def.v" `include "alu_header.v" `include "ucode_header.v" +`include "error_header.v" module microcode( input [`UCODE_ADDR_BITS-1:0] ADDR, @@ -44,7 +45,7 @@ endmodule // verilator lint_off UNUSEDSIGNAL module decoder( - input wire [15:0] CIR,input wire [15:0] FLAGS, output wire [2:0] INSTRUCTION_INFO, output wire [1:0]DECODER_SIGNALS,output reg [`PROC_STATE_BITS-1:0]next_state + input wire [15:0] CIR,input wire [15:0] FLAGS, output wire [2:0] INSTRUCTION_INFO, output wire [`ERROR_BITS:0]DECODER_SIGNALS,output reg [`PROC_STATE_BITS-1:0]next_state ,output reg [2:0]IN_MOD, output reg [2:0]RM, output reg [15:0] PARAM1,output reg [15:0] PARAM2 ,output reg [1:0]in_alu1_sel1,output reg [1:0]in_alu1_sel2,output reg [2:0]OUT_MOD ,output wire [11:0]REGISTER_FILE_CONTROL @@ -65,7 +66,8 @@ assign REGISTER_FILE_CONTROL={reg_write_addr,reg_read_port1_addr,reg_read_port2_ reg Wbit,Sbit,opcode_size; assign INSTRUCTION_INFO={Wbit,Sbit,opcode_size}; -reg ERROR, HALT; +reg [`ERROR_BITS-1:0] ERROR; +reg HALT; assign DECODER_SIGNALS={ERROR,HALT}; @@ -76,14 +78,15 @@ wire [`UCODE_DATA_BITS-1:0] ucode_data; microcode ucode(seq_addr_input,ucode_data); -`define invalid_instruction next_state=`PROC_IF_STATE_ENTRY;ERROR<=1;IN_MOD=3'b011;seq_addr_entry<=`UCODE_NO_INSTRUCTION; +`define invalid_instruction next_state=`PROC_DE_STATE_ENTRY;ERROR<=`ERR_UNIMPL_INSTRUCTION;IN_MOD=3'b011;seq_addr_entry<=`UCODE_NO_INSTRUCTION; //TODO: A possible optimisation for instruction with 8bit parameter and //opcode_size=0 would be to set PARAM1 here instead of sending execution over //to PROC_DE_LOAD_8_PARAM -`define normal_instruction seq_addr_entry<=`UCODE_NO_INSTRUCTION;ERROR<=0;HALT<=0; +`define normal_instruction seq_addr_entry<=`UCODE_NO_INSTRUCTION;ERROR<=`ERR_NO_ERROR;HALT<=0; +`define normal_microcoded ERROR<=`ERR_NO_ERROR;HALT<=0; // I use blocking for basically putting names on the different fields of CIR and // then branching off of that instead of the raw bits. otherwise the code @@ -340,7 +343,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin opcode_size=0; IN_MOD=3'b011; HALT<=1; - ERROR<=0; + ERROR<=`ERR_NO_ERROR; MEM_OR_IO=0; seq_addr_entry<=`UCODE_NO_INSTRUCTION; next_state=`PROC_HALT_STATE; @@ -397,7 +400,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin 3'b000: begin /* Jump on (not) Overflow */ if(FLAGS[11:11]==CIR[8:8]) - next_state=`PROC_IF_STATE_ENTRY; + next_state=`PROC_NEXT_INSTRUCTION; else begin next_state=`PROC_EX_STATE_ENTRY; end @@ -405,21 +408,21 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin 3'b010: begin /* Jump on (not) Zero */ if(FLAGS[6:6]==CIR[8:8]) - next_state=`PROC_IF_STATE_ENTRY; + next_state=`PROC_NEXT_INSTRUCTION; else next_state=`PROC_EX_STATE_ENTRY; end 3'b100: begin /* Jump on (not) Sign */ if(FLAGS[7:7]==CIR[8:8]) - next_state=`PROC_IF_STATE_ENTRY; + next_state=`PROC_NEXT_INSTRUCTION; else next_state=`PROC_EX_STATE_ENTRY; end 3'b101: begin /* Jump on (not) Parity */ if(FLAGS[2:2]==CIR[8:8]) - next_state=`PROC_IF_STATE_ENTRY; + next_state=`PROC_NEXT_INSTRUCTION; else next_state=`PROC_EX_STATE_ENTRY; end @@ -457,6 +460,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin Sbit=1; PARAM2=2; //subtract from sp seq_addr_entry<=`UCODE_CALL_ENTRY; + `normal_microcoded memio_address_select=0; end 11'b1100_0011_???:begin @@ -470,6 +474,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin Sbit=0; PARAM1=2; seq_addr_entry<=`UCODE_RET_ENTRY; + `normal_microcoded memio_address_select=0; end 11'b1010_101?_???:begin @@ -481,6 +486,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin Sbit=0; RM=3'b101; seq_addr_entry<=`UCODE_STOS_ENTRY; + `normal_microcoded PARAM2=(Wbit==1)?2:1; memio_address_select=0; end @@ -494,6 +500,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin PARAM2=2; reg_read_port2_addr={1'b1,CIR[10:8]}; seq_addr_entry<=`UCODE_PUSH_ENTRY; + `normal_microcoded memio_address_select=0; end 11'b1111_011?_000:begin @@ -536,6 +543,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin PARAM1=2; reg_write_addr={1'b1,CIR[10:8]}; seq_addr_entry<=`UCODE_POP_ENTRY; + `normal_microcoded memio_address_select=0; end 11'b1111_1111_100:begin @@ -598,6 +606,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin Sbit=0; PARAM2=2; seq_addr_entry<=`UCODE_INT_ENTRY; + `normal_microcoded memio_address_select=0; end 11'b1110_011?_???:begin @@ -627,6 +636,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin Sbit=0; PARAM1=2; seq_addr_entry<=`UCODE_RET_ENTRY; + `normal_microcoded memio_address_select=0; end default:begin @@ -673,6 +683,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin Wbit=ucode_data[38:38]; memio_address_select=ucode_data[39:39]; MEM_OR_IO=0; + HALT <= 0; end end `undef invalid_instruction diff --git a/system/error_header.v b/system/error_header.v new file mode 100644 index 0000000..2691a9a --- /dev/null +++ b/system/error_header.v @@ -0,0 +1,4 @@ +`define ERROR_BITS 3 +`define ERR_NO_ERROR 3'b000 +`define ERR_UNIMPL_INSTRUCTION 3'b001 +`define ERR_UNIMPL_ADDRESSING_MODE 3'b010 diff --git a/system/proc_state_def.v b/system/proc_state_def.v index 3d8dd53..8203c0a 100644 --- a/system/proc_state_def.v +++ b/system/proc_state_def.v @@ -18,46 +18,29 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -`define PROC_STATE_BITS 6 +`define PROC_STATE_BITS 4 -`define PROC_HALT_STATE 6'b000000 - -/*INSTRUCTION FETCH STATE*/ -`define PROC_IF_STATE_ENTRY 6'b000001 -`define PROC_IF_WRITE_CIR 6'b000010 -`define PROC_IF_STATE_EXTRA_FETCH_SET 6'b000011 -`define PROC_IF_STATE_EXTRA_FETCH 6'b000100 - +`define PROC_HALT_STATE 4'b0000 /*DECODE SATE*/ -`define PROC_DE_STATE_ENTRY 6'b001000 -`define PROC_DE_LOAD_16_PARAM 6'b001001 -`define PROC_DE_LOAD_16_EXTRA_FETCH_SET 6'b001010 -`define PROC_DE_LOAD_16_EXTRA_FETCH 6'b001011 -`define PROC_DE_LOAD_REG_TO_PARAM 6'b001100 +`define PROC_DE_STATE_ENTRY 4'b0001 +`define PROC_DE_LOAD_16_PARAM 4'b0010 +`define PROC_DE_LOAD_REG_TO_PARAM 4'b0011 +`define PROC_DE_LOAD_8_PARAM 4'b0100 /*MEM/IO READ*/ -`define PROC_MEMIO_READ 6'b010000 -`define PROC_MEMIO_READ_SETADDR 6'b010001 -`define PROC_MEMIO_GET_ALIGNED_DATA 6'b010010 /* :) */ -`define PROC_MEMIO_GET_UNALIGNED_DATA 6'b010011 /* :( */ -`define PROC_MEMIO_GET_SECOND_BYTE 6'b010100 -`define PROC_MEMIO_GET_SECOND_BYTE1 6'b010101 -`define PROC_DE_LOAD_8_PARAM 6'b010110 +`define PROC_MEMIO_READ 4'b0101 +`define PROC_MEMIO_READ_SETADDR 4'b0110 /*EXECUTE STATE*/ -`define PROC_EX_STATE_ENTRY 6'b100000 +`define PROC_EX_STATE_ENTRY 4'b1000 /*MEM/IO WRITE*/ -`define PROC_MEMIO_WRITE 6'b101000 -`define PROC_MEMIO_PUT_ALIGNED_16BIT_DATA 6'b101001 -`define PROC_MEMIO_PUT_UNALIGNED_16BIT_DATA 6'b101010 -`define PROC_MEMIO_PUT_BYTE 6'b101011 -`define PROC_MEMIO_WRITE_EXIT 6'b101101 -`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT 6'b101111 -`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2 6'b110010 +`define PROC_MEMIO_WRITE 4'b0111 -`define PROC_NEXT_MICROCODE 6'b111000 +`define PROC_NEXT_INSTRUCTION 4'b1001 -`define PROC_RESET 6'b111100 +`define PROC_NEXT_MICROCODE 4'b1010 + +`define PROC_RESET 4'b1011 diff --git a/system/processor.v b/system/processor.v index 261bf07..15bc2f6 100644 --- a/system/processor.v +++ b/system/processor.v @@ -21,84 +21,109 @@ `include "alu_header.v" `include "config.v" `include "ucode_header.v" +`include "error_header.v" //HALT: active high -//ERROR: active high //IOMEM: 1=IO 0=MEM //write: active low //read: active low //reset: active low -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 BHE,output reg IOMEM, 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:16'hz; +module processor ( input clock, input reset, output [19:0] external_address_bus, inout [15:0] external_data_bus,output read, output write,output BHE,output IOMEM, output reg HALT,output reg [`ERROR_BITS-1:0] ERROR); /*** Global Definitions ***/ - reg [`PROC_STATE_BITS-1:0] state; +/*############ Bus Interface Unit ############################################### */ + +wire [31:0] INSTRUCTION; +reg [1:0] BIU_NEXT_POSITION; +wire VALID_INSTRUCTION; +wire [15:0] INSTRUCTION_LOCATION; +reg [15:0] BIU_ADDRESS_INPUT; +wire [15:0] BIU_DATA; +reg biu_write_request; +reg biu_data_direction; +reg biu_read_request; +wire BIU_VALID_DATA; + +BIU BIU( + clock,reset,external_address_bus,external_data_bus,read,write,BHE,IOMEM, + INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION,BIU_NEXT_POSITION,BIU_ADDRESS_INPUT,BIU_DATA,biu_write_request,biu_read_request,Wbit,BIU_VALID_DATA,MEM_OR_IO +); +assign BIU_DATA= biu_data_direction ? 16'hz : (memio_address_select?reg_read_port1_data:ALU_1O); + /*############ Decoder ########################################################## */ -wire Wbit, Sbit, opcode_size; +reg Wbit, Sbit, opcode_size; +wire DE_Wbit, DE_Sbit, DE_opcode_size; wire [`PROC_STATE_BITS-1:0] next_state; -wire [2:0]RM; +reg [2:0]RM; wire [15:0]DE_PARAM1;// Input param1 form decoder to alu wire [15:0]DE_PARAM2; -wire DE_ERROR,DE_HALT; +wire [2:0]DE_IN_MOD; +wire [2:0]DE_RM; +wire [2:0]DE_OUT_MOD; +wire [`ERROR_BITS-1:0] DE_ERROR; +wire DE_HALT; wire [3:0]DE_reg_read_port1_addr,DE_reg_write_addr,DE_reg_read_port2_addr; wire [11:0]DE_REGISTER_CONTROL; wire [2:0]INSTRUCTION_INFO; -wire [1:0]DECODER_SIGNALS; +wire [`ERROR_BITS:0]DECODER_SIGNALS; wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry; reg SIMPLE_MICRO; /* output simple decodings (=0) or microcode data (=1) */ wire [2:0] DE_instruction_size; reg instruction_size_init; +//TODO : remove completely? +/* verilator lint_off UNUSEDSIGNAL */ wire [2:0] instruction_size; +/* verilator lint_on UNUSEDSIGNAL */ assign instruction_size = instruction_size_init ? 3'b010 : DE_instruction_size; -wire memio_address_select; -wire MEM_OR_IO; - +reg memio_address_select; +wire DE_memio_address_select; +wire DE_MEM_OR_IO; +reg MEM_OR_IO; +wire [1:0] DE_in_alu1_sel1; +wire [1:0] DE_in_alu1_sel2; +reg [`ALU_OP_BITS-1:0] DE_ALU_1OP; decoder decoder( - .CIR(CIR), + .CIR(INSTRUCTION[31:16]), .FLAGS(FLAGS), .INSTRUCTION_INFO(INSTRUCTION_INFO), .DECODER_SIGNALS(DECODER_SIGNALS), .next_state(next_state), - .IN_MOD(IN_MOD), - .RM(RM), + .IN_MOD(DE_IN_MOD), + .RM(DE_RM), .PARAM1(DE_PARAM1), .PARAM2(DE_PARAM2), - .in_alu1_sel1(in_alu1_sel1), - .in_alu1_sel2(in_alu1_sel2), - .OUT_MOD(OUT_MOD), + .in_alu1_sel1(DE_in_alu1_sel1), + .in_alu1_sel2(DE_in_alu1_sel2), + .OUT_MOD(DE_OUT_MOD), .REGISTER_FILE_CONTROL(DE_REGISTER_CONTROL), - .ALU_1OP(ALU_1OP), + .ALU_1OP(DE_ALU_1OP), .seq_addr_entry(ucode_seq_addr_entry), .SIMPLE_MICRO(SIMPLE_MICRO), .seq_addr_input(ucode_seq_addr), .instruction_size(DE_instruction_size), - .memio_address_select(memio_address_select), - .MEM_OR_IO(MEM_OR_IO) + .memio_address_select(DE_memio_address_select), + .MEM_OR_IO(DE_MEM_OR_IO) ); -assign Wbit=INSTRUCTION_INFO[2:2]; -assign Sbit=INSTRUCTION_INFO[1:1]; -assign opcode_size=INSTRUCTION_INFO[0:0]; +assign DE_Wbit=INSTRUCTION_INFO[2:2]; +assign DE_Sbit=INSTRUCTION_INFO[1:1]; +assign DE_opcode_size=INSTRUCTION_INFO[0:0]; assign DE_reg_write_addr=DE_REGISTER_CONTROL[11:8]; assign DE_reg_read_port1_addr=DE_REGISTER_CONTROL[7:4]; assign DE_reg_read_port2_addr=DE_REGISTER_CONTROL[3:0]; assign DE_HALT=DECODER_SIGNALS[0:0]; -assign DE_ERROR=DECODER_SIGNALS[1:1]; +assign DE_ERROR=DECODER_SIGNALS[`ERROR_BITS:1]; reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr; /*############ REGISTERS ########################################################## */ -reg [15:0] CIR; reg [15:0] PARAM1; reg [15:0] PARAM2; @@ -185,114 +210,86 @@ end /* verilator lint_on MULTIDRIVEN */ /*** Processor stages ***/ -`define invalid_instruction state <= `PROC_IF_STATE_ENTRY;ERROR <= 1; +`define unimpl_addressing_mode state <= `PROC_DE_STATE_ENTRY;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE; + +wire [2:0] instr_end; +InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},instr_end); + +reg [23:0] INSTRUCTION_BUFFER; always @(posedge clock) begin case(state) `PROC_RESET:begin + BIU_NEXT_POSITION <= 0; ucode_seq_addr <= `UCODE_NO_INSTRUCTION; - ProgCount <= 'hFFF0;//TODO: Implement Segmentation and set to zero HALT <= 0; - ERROR <= 0; + ERROR <= `ERR_NO_ERROR; SIMPLE_MICRO <= 0; reg_write_we <= 1; instruction_size_init <= 1; - state <= `PROC_IF_STATE_ENTRY; + state <= `PROC_DE_STATE_ENTRY; + reg_write_in_sel <= 2'b00; //only got wirtten in IF + biu_write_request <= 0; + biu_data_direction <= 0; + biu_read_request <= 0; end `PROC_HALT_STATE:begin end - `PROC_IF_STATE_ENTRY:begin - BHE <= 0; - external_address_bus <= {4'b0,ProgCount}; - IOMEM <= 0; - read <= 0; - write <= 1; - reg_write_we <= 1; - state <= `PROC_IF_WRITE_CIR; - reg_write_in_sel <= 2'b00; - end - `PROC_IF_WRITE_CIR:begin - `ifdef DEBUG_PC_ADDRESS - /* Weird (possible bug) where even though the - * testbench stop the clock after ERROR gets - * raised the logic for the rising edge still - * gets triggered printing this debug message. */ - if(ERROR!=1)begin - if(instruction_size==1) - $display("Fetched instruction at %0x",ProgCount - 1); - else - $display("Fetched instruction at %0x",ProgCount - 0); - end - `endif - /*I built the entire decode stage with CIR - * being big endian so just convert it here*/ - - if(instruction_size==1)begin - /*Half on CIR half on this address */ - state <= `PROC_DE_STATE_ENTRY; - if(ProgCount[0:0]==1)begin - CIR <= {CIR[7:0],external_data_bus[15:8]}; - end else begin - CIR <= {CIR[7:0],external_data_bus[7:0]}; - end - ProgCount <= ProgCount+1; - end else begin - if(ProgCount[0:0]==1)begin - /* Half on this address half on the next*/ - ProgCount <= ProgCount+1; - CIR[15:8] <= external_data_bus[15:8]; - state <= `PROC_IF_STATE_EXTRA_FETCH_SET; - end else begin - /* Both on this address! */ - ProgCount <= ProgCount+2; - CIR <= {external_data_bus[7:0],external_data_bus[15:8]}; - state <= `PROC_DE_STATE_ENTRY; - end - end - - end - `PROC_IF_STATE_EXTRA_FETCH_SET:begin - external_address_bus <= {4'b0,ProgCount}; - BHE <= 0; - state <= `PROC_IF_STATE_EXTRA_FETCH; - end - `PROC_IF_STATE_EXTRA_FETCH:begin - CIR[7:0] <= external_data_bus[7:0]; - ProgCount <= ProgCount+1; - state <= `PROC_DE_STATE_ENTRY; - end `PROC_DE_STATE_ENTRY:begin - external_address_bus <= {4'b0,ProgCount}; - if(SIMPLE_MICRO==0)begin - /*This flag is set at reset and jump because - * at IF we need to know the size of the - * previous instruction (specifically if it was - * a single byte and the value would be - * incorrect in both cases. So when it gets - * set reset it only at the start of the next - * 8086 instruction */ - instruction_size_init <= 0; + reg_write_we <= 1; + if(VALID_INSTRUCTION==1) begin + if(SIMPLE_MICRO==0)begin + /*This flag is set at reset and jump because + * at IF we need to know the size of the + * previous instruction (specifically if it was + * a single byte and the value would be + * incorrect in both cases. So when it gets + * set reset it only at the start of the next + * 8086 instruction */ + instruction_size_init <= 0; - /* We cannot set these directly within - * microcode so don't overwrite useful values - * each time the next microcode is executed. - * Note this still allows to set initial values - * at the start of the microcode */ - PARAM1 <= DE_PARAM1; - PARAM2 <= DE_PARAM2; - end - ERROR <= DE_ERROR; - HALT <= DE_HALT; - reg_read_port1_addr <= DE_reg_read_port1_addr; - reg_read_port2_addr <= DE_reg_read_port2_addr; - reg_write_addr <= DE_reg_write_addr; - if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin - /*switch to microcode decoding*/ - ucode_seq_addr <= ucode_seq_addr_entry; - SIMPLE_MICRO <= 1; - /*keep state the same and rerun decode this time with all the data from the microcode rom*/ - end else begin - state <= next_state; + /* We cannot set these directly within + * microcode so don't overwrite useful values + * each tie the next microcode is executed. + * Note this still allows to set initial values + * at the start of the microcode */ + PARAM1 <= DE_PARAM1; + PARAM2 <= DE_PARAM2; + `ifdef DEBUG_PC_ADDRESS + $display("Running command at %04x (%08x)",INSTRUCTION_LOCATION,INSTRUCTION); + `endif + ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end}; + INSTRUCTION_BUFFER<=INSTRUCTION[23:0]; + end + IN_MOD <= DE_IN_MOD; + OUT_MOD <= DE_OUT_MOD; + RM <= DE_RM; + ERROR <= DE_ERROR; + HALT <= DE_HALT; + Wbit <= DE_Wbit; + Sbit <= DE_Sbit; + opcode_size <= DE_opcode_size; + memio_address_select<=DE_memio_address_select; + reg_read_port1_addr <= DE_reg_read_port1_addr; + reg_read_port2_addr <= DE_reg_read_port2_addr; + reg_write_addr <= DE_reg_write_addr; + MEM_OR_IO <= DE_MEM_OR_IO; + in_alu1_sel1 <= DE_in_alu1_sel1; + in_alu1_sel2 <= DE_in_alu1_sel2; + ALU_1OP <= DE_ALU_1OP; + + if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin + /*switch to microcode decoding*/ + ucode_seq_addr <= ucode_seq_addr_entry; + SIMPLE_MICRO <= 1; + /*keep state the same and rerun decode this time with all the data from the microcode rom*/ + BIU_NEXT_POSITION <= 2'b00; + end else begin + state <= next_state; + if ( SIMPLE_MICRO == 0 ) begin + BIU_NEXT_POSITION <= 2'b00; + end + end end end `PROC_DE_LOAD_REG_TO_PARAM:begin @@ -306,72 +303,35 @@ always @(posedge clock) begin if(opcode_size==0)begin if({Sbit,Wbit}==2'b11)begin /*signed "16bit" read*/ - PARAM1 <= {{8{CIR[7:7]}},CIR[7:0]}; + PARAM1 <= {{8{INSTRUCTION_BUFFER[23:23]}},INSTRUCTION_BUFFER[23:16]}; end else begin - PARAM1[7:0] <= CIR[7:0]; + PARAM1[7:0] <= INSTRUCTION_BUFFER[23:16]; end case(IN_MOD) 3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ; default: state <= `PROC_EX_STATE_ENTRY; endcase end else begin - if(ProgCount[0:0]==1)begin - if({Sbit,Wbit}==2'b11)begin - /*signed "16bit" read*/ - PARAM1 <= {{8{external_data_bus[15:15]}},external_data_bus[15:8]}; - end else begin - PARAM1[7:0] <= external_data_bus[15:8]; - end + if({Sbit,Wbit}==2'b11)begin + /*signed "16bit" read*/ + PARAM1 <= {{8{INSTRUCTION_BUFFER[15:15]}},INSTRUCTION_BUFFER[15:8]}; end else begin - if({Sbit,Wbit}==2'b11)begin - /*signed "16bit" read*/ - PARAM1 <= {{8{external_data_bus[7:7]}},external_data_bus[7:0]}; - end else begin - PARAM1[7:0] <= external_data_bus[7:0]; - end + PARAM1[7:0] <= INSTRUCTION_BUFFER[15:8]; end - ProgCount <= ProgCount+1; - case(IN_MOD) - 3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ; - default: state <= `PROC_EX_STATE_ENTRY; - endcase end + case(IN_MOD) + 3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ; + default: state <= `PROC_EX_STATE_ENTRY; + endcase end `PROC_DE_LOAD_16_PARAM:begin if(opcode_size==0)begin - PARAM1[7:0] <= CIR[7:0]; - if(ProgCount[0:0]==1)begin - PARAM1[15:8] <= external_data_bus[15:8]; - end else begin - PARAM1[15:8] <= external_data_bus[7:0]; - end - ProgCount <= ProgCount+1; - case(IN_MOD) - 3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ; - default: state <= `PROC_EX_STATE_ENTRY; - endcase + PARAM1[7:0] <= INSTRUCTION_BUFFER[23:16]; + PARAM1[15:8] <= INSTRUCTION_BUFFER[15:8]; end else begin - if(ProgCount[0:0]==1)begin - ProgCount <= ProgCount+1; - PARAM1[7:0] <= external_data_bus[15:8]; - state <= `PROC_DE_LOAD_16_EXTRA_FETCH_SET; - end else begin - PARAM1 <= external_data_bus; - ProgCount <= ProgCount+2; - case(IN_MOD) - 3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ; - default: state <= `PROC_EX_STATE_ENTRY; - endcase - end + PARAM1[15:8] <= INSTRUCTION_BUFFER[7:0]; + PARAM1[7:0] <= INSTRUCTION_BUFFER[15:8]; end - end - `PROC_DE_LOAD_16_EXTRA_FETCH_SET:begin - external_address_bus <= {4'b0,ProgCount}; - state <= `PROC_DE_LOAD_16_EXTRA_FETCH; - end - `PROC_DE_LOAD_16_EXTRA_FETCH:begin - ProgCount <= ProgCount+1; - PARAM1[15:8] <= external_data_bus[7:0]; case(IN_MOD) 3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ; default: state <= `PROC_EX_STATE_ENTRY; @@ -386,19 +346,19 @@ always @(posedge clock) begin case (RM) 3'b000:begin /*[BX]+[SI]*/ - `invalid_instruction + `unimpl_addressing_mode end 3'b001:begin /*[BX]+[SI]*/ - `invalid_instruction + `unimpl_addressing_mode end 3'b010:begin /*[BP]+[SI]*/ - `invalid_instruction + `unimpl_addressing_mode end 3'b011:begin /*[BP]+[DI]*/ - `invalid_instruction + `unimpl_addressing_mode end 3'b100:begin /*[SI]*/ @@ -412,7 +372,7 @@ always @(posedge clock) begin end 3'b110:begin /*d16 */ - `invalid_instruction + `unimpl_addressing_mode end 3'b111:begin /*[BX]*/ @@ -422,7 +382,7 @@ always @(posedge clock) begin endcase if(IN_MOD!=3'b000)begin /*Actually check if 01 and add the 8bits or if 10 add the 16bits ....*/ - `invalid_instruction; + `unimpl_addressing_mode; end end 3'b110:begin /* SP Indirect read*/ @@ -430,39 +390,31 @@ always @(posedge clock) begin state <= `PROC_MEMIO_READ_SETADDR; end default:begin - `invalid_instruction + `unimpl_addressing_mode end endcase end `PROC_MEMIO_READ_SETADDR:begin if(memio_address_select==0) - external_address_bus <= {4'b0,reg_read_port1_data[15:0]}; + BIU_ADDRESS_INPUT <= reg_read_port1_data[15:0]; else - external_address_bus <= {4'b0,ALU_1O}; - state <= (memio_address_select?ALU_1O[0:0]:reg_read_port1_data[0:0])?`PROC_MEMIO_GET_UNALIGNED_DATA:`PROC_MEMIO_GET_ALIGNED_DATA; - end - `PROC_MEMIO_GET_ALIGNED_DATA:begin - PARAM2 <= (Wbit==1)? external_data_bus : {8'b0,external_data_bus[7:0]} ; - state <= `PROC_EX_STATE_ENTRY; - end - `PROC_MEMIO_GET_UNALIGNED_DATA:begin - PARAM2 <= {8'b0,external_data_bus[15:8]}; - if(Wbit==1) begin - state <= `PROC_MEMIO_GET_SECOND_BYTE; - end else begin + BIU_ADDRESS_INPUT <= ALU_1O; + + if ( BIU_VALID_DATA == 1 ) begin state <= `PROC_EX_STATE_ENTRY; + PARAM2 <= BIU_DATA; + biu_read_request <= 0; + biu_data_direction <= 0; + end else begin + biu_data_direction <= 1; + biu_read_request <= 1; end end - `PROC_MEMIO_GET_SECOND_BYTE:begin - external_address_bus <= external_address_bus+1; - state <= `PROC_MEMIO_GET_SECOND_BYTE1; - end - `PROC_MEMIO_GET_SECOND_BYTE1:begin - PARAM2[15:8] <= external_data_bus[7:0]; - state <= `PROC_EX_STATE_ENTRY; + `PROC_NEXT_INSTRUCTION:begin + BIU_NEXT_POSITION <= 2'b01; + state <= `PROC_DE_STATE_ENTRY; end `PROC_EX_STATE_ENTRY:begin - external_address_bus <= {4'b0,ProgCount}; FLAGS[7:0] <= ALU_1FLAGS[7:0]; case(OUT_MOD) 3'b000, @@ -474,19 +426,19 @@ always @(posedge clock) begin case (RM) /* Duplicate code with write... */ 3'b000:begin /*[BX]+[SI]*/ - `invalid_instruction + `unimpl_addressing_mode end 3'b001:begin /*[BX]+[SI]*/ - `invalid_instruction + `unimpl_addressing_mode end 3'b010:begin /*[BP]+[SI]*/ - `invalid_instruction + `unimpl_addressing_mode end 3'b011:begin /*[BP]+[DI]*/ - `invalid_instruction + `unimpl_addressing_mode end 3'b100:begin /*[SI]*/ @@ -500,7 +452,7 @@ always @(posedge clock) begin end 3'b110:begin /*d16 */ - `invalid_instruction + `unimpl_addressing_mode end 3'b111:begin /*[BX]*/ @@ -508,41 +460,52 @@ always @(posedge clock) begin state <= `PROC_MEMIO_WRITE; end endcase + if(BIU_NEXT_POSITION != 2'b10 ) + BIU_NEXT_POSITION <= 2'b01; end 3'b011:begin reg_write_we <= 0; if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) - state <= `PROC_IF_STATE_ENTRY; + state <= `PROC_DE_STATE_ENTRY; else state <= `PROC_NEXT_MICROCODE; + if(BIU_NEXT_POSITION != 2'b10 ) + BIU_NEXT_POSITION <= 2'b01; end 3'b100:begin /*No output*/ if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) - state <= `PROC_IF_STATE_ENTRY; + state <= `PROC_DE_STATE_ENTRY; else state <= `PROC_NEXT_MICROCODE; + if(BIU_NEXT_POSITION != 2'b10 ) + BIU_NEXT_POSITION <= 2'b01; end 3'b101:begin /* Program Counter*/ - ProgCount <= ALU_1O[15:0]; + BIU_ADDRESS_INPUT <= ALU_1O[15:0]; + BIU_NEXT_POSITION <= 2'b10; instruction_size_init <= 1; if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) - state <= `PROC_IF_STATE_ENTRY; + state <= `PROC_DE_STATE_ENTRY; else state <= `PROC_NEXT_MICROCODE; end 3'b110:begin /* SP Indirect write*/ reg_read_port1_addr <= 4'b1100; state <= `PROC_MEMIO_WRITE; + if(BIU_NEXT_POSITION != 2'b10 ) + BIU_NEXT_POSITION <= 2'b01; end 3'b111:begin /* Write to PRAM1 (for microcode calculations) */ PARAM1 <= ALU_1O; if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) - state <= `PROC_IF_STATE_ENTRY; + state <= `PROC_DE_STATE_ENTRY; else state <= `PROC_NEXT_MICROCODE; + if(BIU_NEXT_POSITION != 2'b10 ) + BIU_NEXT_POSITION <= 2'b01; end default:begin - `invalid_instruction + `unimpl_addressing_mode end endcase end @@ -552,81 +515,37 @@ always @(posedge clock) begin `ifdef DEBUG_MEMORY_WRITES $display("Writing at %04x , %04x",reg_read_port1_data,ALU_1O); `endif - if(memio_address_select==0) - external_address_bus <= {4'b0,reg_read_port1_data[15:0]}; - else - external_address_bus <= {4'b0,ALU_1O}; - IOMEM <= MEM_OR_IO; - state <= (Wbit==0) ? `PROC_MEMIO_PUT_BYTE : (reg_read_port1_data[0:0]?`PROC_MEMIO_PUT_UNALIGNED_16BIT_DATA:`PROC_MEMIO_PUT_ALIGNED_16BIT_DATA) ; - end - `PROC_MEMIO_PUT_UNALIGNED_16BIT_DATA:begin - read <= 1; - BHE <= 0; + biu_write_request <= 1; + if(memio_address_select==0) - data_bus_output_register <= {ALU_1O[7:0],ALU_1O[15:8]}; + BIU_ADDRESS_INPUT <= reg_read_port1_data[15:0]; else - data_bus_output_register <= {reg_read_port1_data[7:0],reg_read_port1_data[15:8]}; - state <= `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT; - end - `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT:begin - write <= 0; - state <= `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2; - end - `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2:begin - write <= 1; - external_address_bus <= external_address_bus+1; - BHE <= 1; - state <= `PROC_MEMIO_WRITE_EXIT; - end - `PROC_MEMIO_PUT_ALIGNED_16BIT_DATA:begin - read <= 1; - data_bus_output_register <= {ALU_1O[15:8],ALU_1O[7:0]}; - state <= `PROC_MEMIO_WRITE_EXIT; - end - `PROC_MEMIO_PUT_BYTE:begin - read <= 1; - state <= `PROC_MEMIO_WRITE_EXIT; - if((memio_address_select?ALU_1O[0:0]:reg_read_port1_data[0:0])==0) begin - BHE <= 1; - if(memio_address_select==0) - data_bus_output_register <= {8'b0,ALU_1O[7:0]}; + BIU_ADDRESS_INPUT <= ALU_1O; + + if (write == 0) begin + biu_write_request <= 0; + if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) + state <= `PROC_DE_STATE_ENTRY; else - data_bus_output_register <= {8'b0,reg_read_port1_data[7:0]}; - end else begin - BHE <= 0; - if(memio_address_select==0) - data_bus_output_register <= {ALU_1O[7:0],8'b0}; - else - data_bus_output_register <= {reg_read_port1_data[7:0],8'b0}; + state <= `PROC_NEXT_MICROCODE; end - end - `PROC_MEMIO_WRITE_EXIT:begin - write <= 0; - if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) - state <= `PROC_IF_STATE_ENTRY; - else - state <= `PROC_NEXT_MICROCODE; + end `PROC_NEXT_MICROCODE:begin - read <= 0; - write <= 1; // maybe we are coming from MEMIO_WRITE - BHE <= 0; ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/ if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin /*Finished microcode*/ SIMPLE_MICRO <= 0; - state <= `PROC_IF_STATE_ENTRY; - end else begin - state <= `PROC_DE_STATE_ENTRY; end + state <= `PROC_DE_STATE_ENTRY; reg_write_we <= 1; end default:begin end endcase end -`undef invalid_instruction +`undef unimpl_addressing_mode endmodule diff --git a/system/system.v b/system/system.v index 0c651bc..7bea1f1 100644 --- a/system/system.v +++ b/system/system.v @@ -18,9 +18,10 @@ along with this program. If not, see . */ `timescale 1ns/1ps +`include "error_header.v" -module system ( input clock,input reset, output [19:0]address_bus, inout [15:0]data_bus,output BHE, output rd, output wr, output IOMEM, output HALT, output ERROR); +module system ( input clock,input reset, output [19:0]address_bus, inout [15:0]data_bus,output BHE, output rd, output wr, output IOMEM, output HALT, output [`ERROR_BITS-1:0] ERROR); processor p(clock,reset,address_bus,data_bus,rd,wr,BHE,IOMEM,HALT,ERROR); doublemem sysmem(address_bus,data_bus,rd,wr,BHE,IOMEM); @@ -33,6 +34,17 @@ initial begin end end +//integer killswitch=0; +//always @(posedge clock) begin +// killswitch <= killswitch +1; +// if( killswitch == 20000 )begin +// if($value$plusargs("MEMDUMP=%s",memdump_name))begin +// $writememh(memdump_name, system.sysmem.memory,0,32767); +// end +// $finish; +// end +//end + always @(negedge wr) begin if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 ) $write("%s" ,data_bus[15:8]); @@ -59,12 +71,25 @@ always @(posedge clock) begin endcase end -always @(posedge ERROR) begin - $display("PROCESSOR RUN INTO AN ERROR.\nCycles run for: %d",cycles-1); - if($value$plusargs("MEMDUMP=%s",memdump_name))begin - $writememh(memdump_name, system.sysmem.memory,0,32767); +always @( ERROR ) begin + if ( ERROR != `ERR_NO_ERROR ) begin + $display("PROCESSOR RUN INTO AN ERROR."); + case (ERROR) + default:begin + end + `ERR_UNIMPL_INSTRUCTION:begin + $display("Unimplemented instruction"); + end + `ERR_UNIMPL_ADDRESSING_MODE: begin + $display("Unimplemented addressing mode"); + end + endcase + $display("Cycles run for: %d",cycles-1); + if($value$plusargs("MEMDUMP=%s",memdump_name))begin + $writememh(memdump_name, system.sysmem.memory,0,32767); + end + finish<=2'd1; end - finish<=2'd1; end integer cycles=0; diff --git a/system/testbench.v b/system/testbench.v index 006567a..aec22e8 100644 --- a/system/testbench.v +++ b/system/testbench.v @@ -27,7 +27,7 @@ reg clk_enable; wire [19:0]address_bus; wire [15:0]data_bus; wire rd,wr,HALT; -wire ERROR; +wire [2:0] ERROR; wire IOMEM; system system( .clock(clock),