First draft of a bus interface unit in an effort to make the CPU pipelined. Currently supports code prefetching

This commit is contained in:
(Tim) Efthimis Kritikos 2023-05-07 13:34:15 +01:00
parent 88a47cc4a9
commit da51dd6da7
9 changed files with 603 additions and 337 deletions

View File

@ -1,43 +1,62 @@
[*] [*]
[*] GTKWave Analyzer v3.3.111 (w)1999-2020 BSI [*] 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] "/home/user/9086/system/boot_code.fst"
[dumpfile_mtime] "Thu Mar 9 04:18:18 2023" [dumpfile_mtime] "Sun May 7 11:35:19 2023"
[dumpfile_size] 8510 [dumpfile_size] 13013
[savefile] "/home/user/9086/gtkwave_savefile.gtkw" [savefile] "/home/user/9086/gtkwave_savefile.gtkw"
[timestart] 198700000000 [timestart] 500000000
[size] 1236 1017 [size] 1524 993
[pos] -1 -1 [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.
[treeopen] TOP.system. [treeopen] TOP.system.
[sst_width] 221 [treeopen] TOP.system.p.
[treeopen] TOP.system.p.BIU.
[sst_width] 263
[signals_width] 293 [signals_width] 293
[sst_expanded] 1 [sst_expanded] 1
[sst_vpaned_height] 312 [sst_vpaned_height] 312
@28 @28
TOP.system.clock TOP.system.clock
TOP.system.reset TOP.system.reset
TOP.system.p.state[5:0]
@22 @22
TOP.system.p.ucode_seq_addr[4:0]
TOP.system.address_bus[19:0] TOP.system.address_bus[19:0]
TOP.system.data_bus[15:0] TOP.system.data_bus[15:0]
TOP.system.p.CIR[15:0] TOP.system.p.BIU.biu_state[3:0]
TOP.system.p.PARAM1[15:0]
TOP.system.p.PARAM2[15:0]
@28 @28
TOP.system.p.read TOP.system.p.read
TOP.system.p.write TOP.system.p.write
@29
TOP.system.IOMEM TOP.system.IOMEM
@22 TOP.system.p.ERROR[2:0]
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.HALT 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] 1
[pattern_trace] 0 [pattern_trace] 0

View File

@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
TOP_LEVEL_SOURCE=system.v 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 EVENT_SIM_TESTBENCH=testbench.v
VERILATOR_TESTBENCH=testbench.cpp VERILATOR_TESTBENCH=testbench.cpp
INCLUDES=proc_state_def.v alu_header.v config.v ucode_header.v 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 #optimisation options
VERILATOR_OPTS += -x-assign fast --x-initial fast VERILATOR_OPTS += -x-assign fast --x-initial fast
#For testing use: #For testing use:
#VERILATOR_OPTS=-x-assign unique --x-initial unique #VERILATOR_OPTS += -x-assign unique --x-initial unique
# COMPILING # COMPILING
${SYSTEM_VVP} : ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES} ${EVENT_SIM_TESTBENCH} ${SYSTEM_VVP} : ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES} ${EVENT_SIM_TESTBENCH}

305
system/biu.v Normal file
View File

@ -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 <http://www.gnu.org/licenses/>. */
//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

View File

@ -20,6 +20,7 @@
`include "proc_state_def.v" `include "proc_state_def.v"
`include "alu_header.v" `include "alu_header.v"
`include "ucode_header.v" `include "ucode_header.v"
`include "error_header.v"
module microcode( module microcode(
input [`UCODE_ADDR_BITS-1:0] ADDR, input [`UCODE_ADDR_BITS-1:0] ADDR,
@ -44,7 +45,7 @@ endmodule
// verilator lint_off UNUSEDSIGNAL // verilator lint_off UNUSEDSIGNAL
module decoder( 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 [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 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 ,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; reg Wbit,Sbit,opcode_size;
assign INSTRUCTION_INFO={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}; assign DECODER_SIGNALS={ERROR,HALT};
@ -76,14 +78,15 @@ wire [`UCODE_DATA_BITS-1:0] ucode_data;
microcode ucode(seq_addr_input,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 //TODO: A possible optimisation for instruction with 8bit parameter and
//opcode_size=0 would be to set PARAM1 here instead of sending execution over //opcode_size=0 would be to set PARAM1 here instead of sending execution over
//to PROC_DE_LOAD_8_PARAM //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 // 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 // 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; opcode_size=0;
IN_MOD=3'b011; IN_MOD=3'b011;
HALT<=1; HALT<=1;
ERROR<=0; ERROR<=`ERR_NO_ERROR;
MEM_OR_IO=0; MEM_OR_IO=0;
seq_addr_entry<=`UCODE_NO_INSTRUCTION; seq_addr_entry<=`UCODE_NO_INSTRUCTION;
next_state=`PROC_HALT_STATE; next_state=`PROC_HALT_STATE;
@ -397,7 +400,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
3'b000: begin 3'b000: begin
/* Jump on (not) Overflow */ /* Jump on (not) Overflow */
if(FLAGS[11:11]==CIR[8:8]) if(FLAGS[11:11]==CIR[8:8])
next_state=`PROC_IF_STATE_ENTRY; next_state=`PROC_NEXT_INSTRUCTION;
else begin else begin
next_state=`PROC_EX_STATE_ENTRY; next_state=`PROC_EX_STATE_ENTRY;
end end
@ -405,21 +408,21 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
3'b010: begin 3'b010: begin
/* Jump on (not) Zero */ /* Jump on (not) Zero */
if(FLAGS[6:6]==CIR[8:8]) if(FLAGS[6:6]==CIR[8:8])
next_state=`PROC_IF_STATE_ENTRY; next_state=`PROC_NEXT_INSTRUCTION;
else else
next_state=`PROC_EX_STATE_ENTRY; next_state=`PROC_EX_STATE_ENTRY;
end end
3'b100: begin 3'b100: begin
/* Jump on (not) Sign */ /* Jump on (not) Sign */
if(FLAGS[7:7]==CIR[8:8]) if(FLAGS[7:7]==CIR[8:8])
next_state=`PROC_IF_STATE_ENTRY; next_state=`PROC_NEXT_INSTRUCTION;
else else
next_state=`PROC_EX_STATE_ENTRY; next_state=`PROC_EX_STATE_ENTRY;
end end
3'b101: begin 3'b101: begin
/* Jump on (not) Parity */ /* Jump on (not) Parity */
if(FLAGS[2:2]==CIR[8:8]) if(FLAGS[2:2]==CIR[8:8])
next_state=`PROC_IF_STATE_ENTRY; next_state=`PROC_NEXT_INSTRUCTION;
else else
next_state=`PROC_EX_STATE_ENTRY; next_state=`PROC_EX_STATE_ENTRY;
end end
@ -457,6 +460,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Sbit=1; Sbit=1;
PARAM2=2; //subtract from sp PARAM2=2; //subtract from sp
seq_addr_entry<=`UCODE_CALL_ENTRY; seq_addr_entry<=`UCODE_CALL_ENTRY;
`normal_microcoded
memio_address_select=0; memio_address_select=0;
end end
11'b1100_0011_???:begin 11'b1100_0011_???:begin
@ -470,6 +474,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Sbit=0; Sbit=0;
PARAM1=2; PARAM1=2;
seq_addr_entry<=`UCODE_RET_ENTRY; seq_addr_entry<=`UCODE_RET_ENTRY;
`normal_microcoded
memio_address_select=0; memio_address_select=0;
end end
11'b1010_101?_???:begin 11'b1010_101?_???:begin
@ -481,6 +486,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Sbit=0; Sbit=0;
RM=3'b101; RM=3'b101;
seq_addr_entry<=`UCODE_STOS_ENTRY; seq_addr_entry<=`UCODE_STOS_ENTRY;
`normal_microcoded
PARAM2=(Wbit==1)?2:1; PARAM2=(Wbit==1)?2:1;
memio_address_select=0; memio_address_select=0;
end end
@ -494,6 +500,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
PARAM2=2; PARAM2=2;
reg_read_port2_addr={1'b1,CIR[10:8]}; reg_read_port2_addr={1'b1,CIR[10:8]};
seq_addr_entry<=`UCODE_PUSH_ENTRY; seq_addr_entry<=`UCODE_PUSH_ENTRY;
`normal_microcoded
memio_address_select=0; memio_address_select=0;
end end
11'b1111_011?_000:begin 11'b1111_011?_000:begin
@ -536,6 +543,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
PARAM1=2; PARAM1=2;
reg_write_addr={1'b1,CIR[10:8]}; reg_write_addr={1'b1,CIR[10:8]};
seq_addr_entry<=`UCODE_POP_ENTRY; seq_addr_entry<=`UCODE_POP_ENTRY;
`normal_microcoded
memio_address_select=0; memio_address_select=0;
end end
11'b1111_1111_100:begin 11'b1111_1111_100:begin
@ -598,6 +606,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Sbit=0; Sbit=0;
PARAM2=2; PARAM2=2;
seq_addr_entry<=`UCODE_INT_ENTRY; seq_addr_entry<=`UCODE_INT_ENTRY;
`normal_microcoded
memio_address_select=0; memio_address_select=0;
end end
11'b1110_011?_???:begin 11'b1110_011?_???:begin
@ -627,6 +636,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Sbit=0; Sbit=0;
PARAM1=2; PARAM1=2;
seq_addr_entry<=`UCODE_RET_ENTRY; seq_addr_entry<=`UCODE_RET_ENTRY;
`normal_microcoded
memio_address_select=0; memio_address_select=0;
end end
default:begin default:begin
@ -673,6 +683,7 @@ always @( CIR or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=ucode_data[38:38]; Wbit=ucode_data[38:38];
memio_address_select=ucode_data[39:39]; memio_address_select=ucode_data[39:39];
MEM_OR_IO=0; MEM_OR_IO=0;
HALT <= 0;
end end
end end
`undef invalid_instruction `undef invalid_instruction

4
system/error_header.v Normal file
View File

@ -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

View File

@ -18,46 +18,29 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */ along with this program. If not, see <http://www.gnu.org/licenses/>. */
`define PROC_STATE_BITS 6 `define PROC_STATE_BITS 4
`define PROC_HALT_STATE 6'b000000 `define PROC_HALT_STATE 4'b0000
/*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
/*DECODE SATE*/ /*DECODE SATE*/
`define PROC_DE_STATE_ENTRY 6'b001000 `define PROC_DE_STATE_ENTRY 4'b0001
`define PROC_DE_LOAD_16_PARAM 6'b001001 `define PROC_DE_LOAD_16_PARAM 4'b0010
`define PROC_DE_LOAD_16_EXTRA_FETCH_SET 6'b001010 `define PROC_DE_LOAD_REG_TO_PARAM 4'b0011
`define PROC_DE_LOAD_16_EXTRA_FETCH 6'b001011 `define PROC_DE_LOAD_8_PARAM 4'b0100
`define PROC_DE_LOAD_REG_TO_PARAM 6'b001100
/*MEM/IO READ*/ /*MEM/IO READ*/
`define PROC_MEMIO_READ 6'b010000 `define PROC_MEMIO_READ 4'b0101
`define PROC_MEMIO_READ_SETADDR 6'b010001 `define PROC_MEMIO_READ_SETADDR 4'b0110
`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
/*EXECUTE STATE*/ /*EXECUTE STATE*/
`define PROC_EX_STATE_ENTRY 6'b100000 `define PROC_EX_STATE_ENTRY 4'b1000
/*MEM/IO WRITE*/ /*MEM/IO WRITE*/
`define PROC_MEMIO_WRITE 6'b101000 `define PROC_MEMIO_WRITE 4'b0111
`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_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

View File

@ -21,84 +21,109 @@
`include "alu_header.v" `include "alu_header.v"
`include "config.v" `include "config.v"
`include "ucode_header.v" `include "ucode_header.v"
`include "error_header.v"
//HALT: active high //HALT: active high
//ERROR: active high
//IOMEM: 1=IO 0=MEM //IOMEM: 1=IO 0=MEM
//write: active low //write: active low
//read: active low //read: active low
//reset: 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); 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);
/*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;
/*** Global Definitions ***/ /*** Global Definitions ***/
reg [`PROC_STATE_BITS-1:0] state; 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 ########################################################## */ /*############ 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 [`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_PARAM1;// Input param1 form decoder to alu
wire [15:0]DE_PARAM2; 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 [3:0]DE_reg_read_port1_addr,DE_reg_write_addr,DE_reg_read_port2_addr;
wire [11:0]DE_REGISTER_CONTROL; wire [11:0]DE_REGISTER_CONTROL;
wire [2:0]INSTRUCTION_INFO; 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; wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry;
reg SIMPLE_MICRO; /* output simple decodings (=0) or microcode data (=1) */ reg SIMPLE_MICRO; /* output simple decodings (=0) or microcode data (=1) */
wire [2:0] DE_instruction_size; wire [2:0] DE_instruction_size;
reg instruction_size_init; reg instruction_size_init;
//TODO : remove completely?
/* verilator lint_off UNUSEDSIGNAL */
wire [2:0] instruction_size; wire [2:0] instruction_size;
/* verilator lint_on UNUSEDSIGNAL */
assign instruction_size = instruction_size_init ? 3'b010 : DE_instruction_size; assign instruction_size = instruction_size_init ? 3'b010 : DE_instruction_size;
wire memio_address_select; reg memio_address_select;
wire MEM_OR_IO; 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( decoder decoder(
.CIR(CIR), .CIR(INSTRUCTION[31:16]),
.FLAGS(FLAGS), .FLAGS(FLAGS),
.INSTRUCTION_INFO(INSTRUCTION_INFO), .INSTRUCTION_INFO(INSTRUCTION_INFO),
.DECODER_SIGNALS(DECODER_SIGNALS), .DECODER_SIGNALS(DECODER_SIGNALS),
.next_state(next_state), .next_state(next_state),
.IN_MOD(IN_MOD), .IN_MOD(DE_IN_MOD),
.RM(RM), .RM(DE_RM),
.PARAM1(DE_PARAM1), .PARAM1(DE_PARAM1),
.PARAM2(DE_PARAM2), .PARAM2(DE_PARAM2),
.in_alu1_sel1(in_alu1_sel1), .in_alu1_sel1(DE_in_alu1_sel1),
.in_alu1_sel2(in_alu1_sel2), .in_alu1_sel2(DE_in_alu1_sel2),
.OUT_MOD(OUT_MOD), .OUT_MOD(DE_OUT_MOD),
.REGISTER_FILE_CONTROL(DE_REGISTER_CONTROL), .REGISTER_FILE_CONTROL(DE_REGISTER_CONTROL),
.ALU_1OP(ALU_1OP), .ALU_1OP(DE_ALU_1OP),
.seq_addr_entry(ucode_seq_addr_entry), .seq_addr_entry(ucode_seq_addr_entry),
.SIMPLE_MICRO(SIMPLE_MICRO), .SIMPLE_MICRO(SIMPLE_MICRO),
.seq_addr_input(ucode_seq_addr), .seq_addr_input(ucode_seq_addr),
.instruction_size(DE_instruction_size), .instruction_size(DE_instruction_size),
.memio_address_select(memio_address_select), .memio_address_select(DE_memio_address_select),
.MEM_OR_IO(MEM_OR_IO) .MEM_OR_IO(DE_MEM_OR_IO)
); );
assign Wbit=INSTRUCTION_INFO[2:2]; assign DE_Wbit=INSTRUCTION_INFO[2:2];
assign Sbit=INSTRUCTION_INFO[1:1]; assign DE_Sbit=INSTRUCTION_INFO[1:1];
assign opcode_size=INSTRUCTION_INFO[0:0]; assign DE_opcode_size=INSTRUCTION_INFO[0:0];
assign DE_reg_write_addr=DE_REGISTER_CONTROL[11:8]; 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_port1_addr=DE_REGISTER_CONTROL[7:4];
assign DE_reg_read_port2_addr=DE_REGISTER_CONTROL[3:0]; assign DE_reg_read_port2_addr=DE_REGISTER_CONTROL[3:0];
assign DE_HALT=DECODER_SIGNALS[0: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; reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr;
/*############ REGISTERS ########################################################## */ /*############ REGISTERS ########################################################## */
reg [15:0] CIR;
reg [15:0] PARAM1; reg [15:0] PARAM1;
reg [15:0] PARAM2; reg [15:0] PARAM2;
@ -185,114 +210,86 @@ end
/* verilator lint_on MULTIDRIVEN */ /* verilator lint_on MULTIDRIVEN */
/*** Processor stages ***/ /*** 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 always @(posedge clock) begin
case(state) case(state)
`PROC_RESET:begin `PROC_RESET:begin
BIU_NEXT_POSITION <= 0;
ucode_seq_addr <= `UCODE_NO_INSTRUCTION; ucode_seq_addr <= `UCODE_NO_INSTRUCTION;
ProgCount <= 'hFFF0;//TODO: Implement Segmentation and set to zero
HALT <= 0; HALT <= 0;
ERROR <= 0; ERROR <= `ERR_NO_ERROR;
SIMPLE_MICRO <= 0; SIMPLE_MICRO <= 0;
reg_write_we <= 1; reg_write_we <= 1;
instruction_size_init <= 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 end
`PROC_HALT_STATE:begin `PROC_HALT_STATE:begin
end 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 `PROC_DE_STATE_ENTRY:begin
external_address_bus <= {4'b0,ProgCount}; reg_write_we <= 1;
if(SIMPLE_MICRO==0)begin if(VALID_INSTRUCTION==1) begin
/*This flag is set at reset and jump because if(SIMPLE_MICRO==0)begin
* at IF we need to know the size of the /*This flag is set at reset and jump because
* previous instruction (specifically if it was * at IF we need to know the size of the
* a single byte and the value would be * previous instruction (specifically if it was
* incorrect in both cases. So when it gets * a single byte and the value would be
* set reset it only at the start of the next * incorrect in both cases. So when it gets
* 8086 instruction */ * set reset it only at the start of the next
instruction_size_init <= 0; * 8086 instruction */
instruction_size_init <= 0;
/* We cannot set these directly within /* We cannot set these directly within
* microcode so don't overwrite useful values * microcode so don't overwrite useful values
* each time the next microcode is executed. * each tie the next microcode is executed.
* Note this still allows to set initial values * Note this still allows to set initial values
* at the start of the microcode */ * at the start of the microcode */
PARAM1 <= DE_PARAM1; PARAM1 <= DE_PARAM1;
PARAM2 <= DE_PARAM2; PARAM2 <= DE_PARAM2;
end `ifdef DEBUG_PC_ADDRESS
ERROR <= DE_ERROR; $display("Running command at %04x (%08x)",INSTRUCTION_LOCATION,INSTRUCTION);
HALT <= DE_HALT; `endif
reg_read_port1_addr <= DE_reg_read_port1_addr; ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end};
reg_read_port2_addr <= DE_reg_read_port2_addr; INSTRUCTION_BUFFER<=INSTRUCTION[23:0];
reg_write_addr <= DE_reg_write_addr; end
if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin IN_MOD <= DE_IN_MOD;
/*switch to microcode decoding*/ OUT_MOD <= DE_OUT_MOD;
ucode_seq_addr <= ucode_seq_addr_entry; RM <= DE_RM;
SIMPLE_MICRO <= 1; ERROR <= DE_ERROR;
/*keep state the same and rerun decode this time with all the data from the microcode rom*/ HALT <= DE_HALT;
end else begin Wbit <= DE_Wbit;
state <= next_state; 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
end end
`PROC_DE_LOAD_REG_TO_PARAM:begin `PROC_DE_LOAD_REG_TO_PARAM:begin
@ -306,72 +303,35 @@ always @(posedge clock) begin
if(opcode_size==0)begin if(opcode_size==0)begin
if({Sbit,Wbit}==2'b11)begin if({Sbit,Wbit}==2'b11)begin
/*signed "16bit" read*/ /*signed "16bit" read*/
PARAM1 <= {{8{CIR[7:7]}},CIR[7:0]}; PARAM1 <= {{8{INSTRUCTION_BUFFER[23:23]}},INSTRUCTION_BUFFER[23:16]};
end else begin end else begin
PARAM1[7:0] <= CIR[7:0]; PARAM1[7:0] <= INSTRUCTION_BUFFER[23:16];
end end
case(IN_MOD) case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ; 3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY; default: state <= `PROC_EX_STATE_ENTRY;
endcase endcase
end else begin end else begin
if(ProgCount[0:0]==1)begin if({Sbit,Wbit}==2'b11)begin
if({Sbit,Wbit}==2'b11)begin /*signed "16bit" read*/
/*signed "16bit" read*/ PARAM1 <= {{8{INSTRUCTION_BUFFER[15:15]}},INSTRUCTION_BUFFER[15:8]};
PARAM1 <= {{8{external_data_bus[15:15]}},external_data_bus[15:8]};
end else begin
PARAM1[7:0] <= external_data_bus[15:8];
end
end else begin end else begin
if({Sbit,Wbit}==2'b11)begin PARAM1[7:0] <= INSTRUCTION_BUFFER[15:8];
/*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
end 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 end
case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY;
endcase
end end
`PROC_DE_LOAD_16_PARAM:begin `PROC_DE_LOAD_16_PARAM:begin
if(opcode_size==0)begin if(opcode_size==0)begin
PARAM1[7:0] <= CIR[7:0]; PARAM1[7:0] <= INSTRUCTION_BUFFER[23:16];
if(ProgCount[0:0]==1)begin PARAM1[15:8] <= INSTRUCTION_BUFFER[15:8];
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
end else begin end else begin
if(ProgCount[0:0]==1)begin PARAM1[15:8] <= INSTRUCTION_BUFFER[7:0];
ProgCount <= ProgCount+1; PARAM1[7:0] <= INSTRUCTION_BUFFER[15:8];
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
end 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) case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ; 3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY; default: state <= `PROC_EX_STATE_ENTRY;
@ -386,19 +346,19 @@ always @(posedge clock) begin
case (RM) case (RM)
3'b000:begin 3'b000:begin
/*[BX]+[SI]*/ /*[BX]+[SI]*/
`invalid_instruction `unimpl_addressing_mode
end end
3'b001:begin 3'b001:begin
/*[BX]+[SI]*/ /*[BX]+[SI]*/
`invalid_instruction `unimpl_addressing_mode
end end
3'b010:begin 3'b010:begin
/*[BP]+[SI]*/ /*[BP]+[SI]*/
`invalid_instruction `unimpl_addressing_mode
end end
3'b011:begin 3'b011:begin
/*[BP]+[DI]*/ /*[BP]+[DI]*/
`invalid_instruction `unimpl_addressing_mode
end end
3'b100:begin 3'b100:begin
/*[SI]*/ /*[SI]*/
@ -412,7 +372,7 @@ always @(posedge clock) begin
end end
3'b110:begin 3'b110:begin
/*d16 */ /*d16 */
`invalid_instruction `unimpl_addressing_mode
end end
3'b111:begin 3'b111:begin
/*[BX]*/ /*[BX]*/
@ -422,7 +382,7 @@ always @(posedge clock) begin
endcase endcase
if(IN_MOD!=3'b000)begin if(IN_MOD!=3'b000)begin
/*Actually check if 01 and add the 8bits or if 10 add the 16bits ....*/ /*Actually check if 01 and add the 8bits or if 10 add the 16bits ....*/
`invalid_instruction; `unimpl_addressing_mode;
end end
end end
3'b110:begin /* SP Indirect read*/ 3'b110:begin /* SP Indirect read*/
@ -430,39 +390,31 @@ always @(posedge clock) begin
state <= `PROC_MEMIO_READ_SETADDR; state <= `PROC_MEMIO_READ_SETADDR;
end end
default:begin default:begin
`invalid_instruction `unimpl_addressing_mode
end end
endcase endcase
end end
`PROC_MEMIO_READ_SETADDR:begin `PROC_MEMIO_READ_SETADDR:begin
if(memio_address_select==0) 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 else
external_address_bus <= {4'b0,ALU_1O}; BIU_ADDRESS_INPUT <= 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 if ( BIU_VALID_DATA == 1 ) begin
`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
state <= `PROC_EX_STATE_ENTRY; 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
end end
`PROC_MEMIO_GET_SECOND_BYTE:begin `PROC_NEXT_INSTRUCTION:begin
external_address_bus <= external_address_bus+1; BIU_NEXT_POSITION <= 2'b01;
state <= `PROC_MEMIO_GET_SECOND_BYTE1; state <= `PROC_DE_STATE_ENTRY;
end
`PROC_MEMIO_GET_SECOND_BYTE1:begin
PARAM2[15:8] <= external_data_bus[7:0];
state <= `PROC_EX_STATE_ENTRY;
end end
`PROC_EX_STATE_ENTRY:begin `PROC_EX_STATE_ENTRY:begin
external_address_bus <= {4'b0,ProgCount};
FLAGS[7:0] <= ALU_1FLAGS[7:0]; FLAGS[7:0] <= ALU_1FLAGS[7:0];
case(OUT_MOD) case(OUT_MOD)
3'b000, 3'b000,
@ -474,19 +426,19 @@ always @(posedge clock) begin
case (RM) /* Duplicate code with write... */ case (RM) /* Duplicate code with write... */
3'b000:begin 3'b000:begin
/*[BX]+[SI]*/ /*[BX]+[SI]*/
`invalid_instruction `unimpl_addressing_mode
end end
3'b001:begin 3'b001:begin
/*[BX]+[SI]*/ /*[BX]+[SI]*/
`invalid_instruction `unimpl_addressing_mode
end end
3'b010:begin 3'b010:begin
/*[BP]+[SI]*/ /*[BP]+[SI]*/
`invalid_instruction `unimpl_addressing_mode
end end
3'b011:begin 3'b011:begin
/*[BP]+[DI]*/ /*[BP]+[DI]*/
`invalid_instruction `unimpl_addressing_mode
end end
3'b100:begin 3'b100:begin
/*[SI]*/ /*[SI]*/
@ -500,7 +452,7 @@ always @(posedge clock) begin
end end
3'b110:begin 3'b110:begin
/*d16 */ /*d16 */
`invalid_instruction `unimpl_addressing_mode
end end
3'b111:begin 3'b111:begin
/*[BX]*/ /*[BX]*/
@ -508,41 +460,52 @@ always @(posedge clock) begin
state <= `PROC_MEMIO_WRITE; state <= `PROC_MEMIO_WRITE;
end end
endcase endcase
if(BIU_NEXT_POSITION != 2'b10 )
BIU_NEXT_POSITION <= 2'b01;
end end
3'b011:begin 3'b011:begin
reg_write_we <= 0; reg_write_we <= 0;
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY; state <= `PROC_DE_STATE_ENTRY;
else else
state <= `PROC_NEXT_MICROCODE; state <= `PROC_NEXT_MICROCODE;
if(BIU_NEXT_POSITION != 2'b10 )
BIU_NEXT_POSITION <= 2'b01;
end end
3'b100:begin /*No output*/ 3'b100:begin /*No output*/
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY; state <= `PROC_DE_STATE_ENTRY;
else else
state <= `PROC_NEXT_MICROCODE; state <= `PROC_NEXT_MICROCODE;
if(BIU_NEXT_POSITION != 2'b10 )
BIU_NEXT_POSITION <= 2'b01;
end end
3'b101:begin /* Program Counter*/ 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; instruction_size_init <= 1;
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY; state <= `PROC_DE_STATE_ENTRY;
else else
state <= `PROC_NEXT_MICROCODE; state <= `PROC_NEXT_MICROCODE;
end end
3'b110:begin /* SP Indirect write*/ 3'b110:begin /* SP Indirect write*/
reg_read_port1_addr <= 4'b1100; reg_read_port1_addr <= 4'b1100;
state <= `PROC_MEMIO_WRITE; state <= `PROC_MEMIO_WRITE;
if(BIU_NEXT_POSITION != 2'b10 )
BIU_NEXT_POSITION <= 2'b01;
end end
3'b111:begin /* Write to PRAM1 (for microcode calculations) */ 3'b111:begin /* Write to PRAM1 (for microcode calculations) */
PARAM1 <= ALU_1O; PARAM1 <= ALU_1O;
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION) if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY; state <= `PROC_DE_STATE_ENTRY;
else else
state <= `PROC_NEXT_MICROCODE; state <= `PROC_NEXT_MICROCODE;
if(BIU_NEXT_POSITION != 2'b10 )
BIU_NEXT_POSITION <= 2'b01;
end end
default:begin default:begin
`invalid_instruction `unimpl_addressing_mode
end end
endcase endcase
end end
@ -552,81 +515,37 @@ always @(posedge clock) begin
`ifdef DEBUG_MEMORY_WRITES `ifdef DEBUG_MEMORY_WRITES
$display("Writing at %04x , %04x",reg_read_port1_data,ALU_1O); $display("Writing at %04x , %04x",reg_read_port1_data,ALU_1O);
`endif `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; biu_write_request <= 1;
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;
if(memio_address_select==0) 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 else
data_bus_output_register <= {reg_read_port1_data[7:0],reg_read_port1_data[15:8]}; BIU_ADDRESS_INPUT <= ALU_1O;
state <= `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT;
end if (write == 0) begin
`PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT:begin biu_write_request <= 0;
write <= 0; if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2; state <= `PROC_DE_STATE_ENTRY;
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]};
else else
data_bus_output_register <= {8'b0,reg_read_port1_data[7:0]}; state <= `PROC_NEXT_MICROCODE;
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};
end 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 end
`PROC_NEXT_MICROCODE:begin `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*/ ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/
if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin
/*Finished microcode*/ /*Finished microcode*/
SIMPLE_MICRO <= 0; SIMPLE_MICRO <= 0;
state <= `PROC_IF_STATE_ENTRY;
end else begin
state <= `PROC_DE_STATE_ENTRY;
end end
state <= `PROC_DE_STATE_ENTRY;
reg_write_we <= 1; reg_write_we <= 1;
end end
default:begin default:begin
end end
endcase endcase
end end
`undef invalid_instruction `undef unimpl_addressing_mode
endmodule endmodule

View File

@ -18,9 +18,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */ along with this program. If not, see <http://www.gnu.org/licenses/>. */
`timescale 1ns/1ps `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); processor p(clock,reset,address_bus,data_bus,rd,wr,BHE,IOMEM,HALT,ERROR);
doublemem sysmem(address_bus,data_bus,rd,wr,BHE,IOMEM); doublemem sysmem(address_bus,data_bus,rd,wr,BHE,IOMEM);
@ -33,6 +34,17 @@ initial begin
end end
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 always @(negedge wr) begin
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 ) if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )
$write("%s" ,data_bus[15:8]); $write("%s" ,data_bus[15:8]);
@ -59,12 +71,25 @@ always @(posedge clock) begin
endcase endcase
end end
always @(posedge ERROR) begin always @( ERROR ) begin
$display("PROCESSOR RUN INTO AN ERROR.\nCycles run for: %d",cycles-1); if ( ERROR != `ERR_NO_ERROR ) begin
if($value$plusargs("MEMDUMP=%s",memdump_name))begin $display("PROCESSOR RUN INTO AN ERROR.");
$writememh(memdump_name, system.sysmem.memory,0,32767); 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 end
finish<=2'd1;
end end
integer cycles=0; integer cycles=0;

View File

@ -27,7 +27,7 @@ reg clk_enable;
wire [19:0]address_bus; wire [19:0]address_bus;
wire [15:0]data_bus; wire [15:0]data_bus;
wire rd,wr,HALT; wire rd,wr,HALT;
wire ERROR; wire [2:0] ERROR;
wire IOMEM; wire IOMEM;
system system( .clock(clock), system system( .clock(clock),