mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-01-17 16:43:22 +00:00
add 8088 CPU Core
This commit is contained in:
parent
625802aab9
commit
bc68a4b293
766
common/CPU/8088/biu_max.v
Normal file
766
common/CPU/8088/biu_max.v
Normal file
@ -0,0 +1,766 @@
|
||||
//
|
||||
//
|
||||
// File Name : biu_max.v
|
||||
// Used on :
|
||||
// Author : Ted Fried, MicroCore Labs
|
||||
// Creation : 10/8/2015
|
||||
// Code Type : Synthesizable
|
||||
//
|
||||
// Description:
|
||||
// ============
|
||||
//
|
||||
// Bus Interface Unit of the i8088 processor in Maximum Bus Mode
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// Modification History:
|
||||
// =====================
|
||||
//
|
||||
// Revision 1.0 10/8/15
|
||||
// Initial revision
|
||||
//
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2020 Ted Fried
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
module biu_max
|
||||
(
|
||||
input CORE_CLK_INT, // Core Clock
|
||||
|
||||
|
||||
input CLK, // 8088 Pins
|
||||
input RESET_INT,
|
||||
input READY_IN,
|
||||
input NMI,
|
||||
input INTR,
|
||||
output reg LOCK_n,
|
||||
output reg AD_OE,
|
||||
output reg [19:0] AD_OUT,
|
||||
input [7:0] AD_IN,
|
||||
output reg S6_3_MUX,
|
||||
output reg [2:0] S2_S0_OUT,
|
||||
|
||||
|
||||
input [15:0] EU_BIU_COMMAND, // EU to BIU Signals
|
||||
input [15:0] EU_BIU_DATAOUT,
|
||||
input [15:0] EU_REGISTER_R3,
|
||||
input EU_PREFIX_LOCK,
|
||||
|
||||
|
||||
output BIU_DONE, // BIU to EU Signals
|
||||
output BIU_CLK_COUNTER_ZERO,
|
||||
output [1:0] BIU_SEGMENT,
|
||||
output BIU_NMI_CAUGHT,
|
||||
input BIU_NMI_DEBOUNCE,
|
||||
output reg BIU_INTR,
|
||||
|
||||
output [7:0] PFQ_TOP_BYTE,
|
||||
output PFQ_EMPTY,
|
||||
output[15:0] PFQ_ADDR_OUT,
|
||||
|
||||
output [15:0] BIU_REGISTER_ES,
|
||||
output [15:0] BIU_REGISTER_SS,
|
||||
output [15:0] BIU_REGISTER_CS,
|
||||
output [15:0] BIU_REGISTER_DS,
|
||||
output [15:0] BIU_REGISTER_RM,
|
||||
output [15:0] BIU_REGISTER_REG,
|
||||
output [15:0] BIU_RETURN_DATA
|
||||
|
||||
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Internal Signals
|
||||
|
||||
reg biu_done_int;
|
||||
reg biu_lock_n_int;
|
||||
reg byte_num;
|
||||
reg clk_d1;
|
||||
reg clk_d2;
|
||||
reg clk_d3;
|
||||
reg clk_d4;
|
||||
reg eu_biu_req_caught;
|
||||
reg eu_biu_req_d1;
|
||||
reg eu_prefix_lock_d1;
|
||||
reg eu_prefix_lock_d2;
|
||||
reg intr_d1;
|
||||
reg intr_d2;
|
||||
reg intr_d3;
|
||||
reg nmi_caught;
|
||||
reg nmi_d1;
|
||||
reg nmi_d2;
|
||||
reg nmi_d3;
|
||||
reg pfq_write;
|
||||
reg ready_d1;
|
||||
reg ready_d2;
|
||||
reg ready_d3;
|
||||
reg word_cycle;
|
||||
wire eu_biu_req;
|
||||
wire eu_prefix_seg;
|
||||
wire pfq_empty;
|
||||
reg [7:0] ad_in_int;
|
||||
reg [19:0] addr_out_temp;
|
||||
reg [7:0] biu_state;
|
||||
reg [15:0] biu_register_cs;
|
||||
reg [15:0] biu_register_es;
|
||||
reg [15:0] biu_register_ss;
|
||||
reg [15:0] biu_register_ds;
|
||||
reg [15:0] biu_register_rm;
|
||||
reg [15:0] biu_register_reg;
|
||||
reg [15:0] biu_register_cs_d1;
|
||||
reg [15:0] biu_register_es_d1;
|
||||
reg [15:0] biu_register_ss_d1;
|
||||
reg [15:0] biu_register_ds_d1;
|
||||
reg [15:0] biu_register_rm_d1;
|
||||
reg [15:0] biu_register_reg_d1;
|
||||
reg [15:0] biu_register_cs_d2;
|
||||
reg [15:0] biu_register_es_d2;
|
||||
reg [15:0] biu_register_ss_d2;
|
||||
reg [15:0] biu_register_ds_d2;
|
||||
reg [15:0] biu_register_rm_d2;
|
||||
reg [15:0] biu_register_reg_d2;
|
||||
reg [15:0] biu_return_data_int;
|
||||
reg [15:0] biu_return_data_int_d1;
|
||||
reg [15:0] biu_return_data_int_d2;
|
||||
reg [12:0] clock_cycle_counter;
|
||||
reg [15:0] eu_register_r3_d;
|
||||
reg [7:0] latched_data_in;
|
||||
reg [15:0] pfq_addr_out;
|
||||
reg [7:0] pfq_entry0;
|
||||
reg [7:0] pfq_entry1;
|
||||
reg [7:0] pfq_entry2;
|
||||
reg [7:0] pfq_entry3;
|
||||
reg [15:0] pfq_addr_in;
|
||||
reg [7:0] pfq_top_byte_int_d1;
|
||||
reg [15:0] pfq_addr_out_d1;
|
||||
reg [2:0] s_bits;
|
||||
reg [2:0] s2_s0_out_int;
|
||||
wire [15:0] biu_muxed_segment;
|
||||
wire [1:0] biu_segment;
|
||||
wire [1:0] eu_biu_strobe;
|
||||
wire [1:0] eu_biu_segment;
|
||||
wire [4:0] eu_biu_req_code;
|
||||
wire [1:0] eu_qs_out;
|
||||
wire [1:0] eu_segment_override_value;
|
||||
wire [7:0] pfq_top_byte_int;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// BIU Combinationals
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
// Outputs to the EU
|
||||
//
|
||||
assign BIU_DONE = biu_done_int;
|
||||
assign PFQ_EMPTY = pfq_empty;
|
||||
assign PFQ_ADDR_OUT = pfq_addr_out_d1;
|
||||
assign BIU_SEGMENT = biu_segment;
|
||||
assign BIU_REGISTER_ES = biu_register_es_d2;
|
||||
assign BIU_REGISTER_SS = biu_register_ss_d2;
|
||||
assign BIU_REGISTER_CS = biu_register_cs_d2;
|
||||
assign BIU_REGISTER_DS = biu_register_ds_d2;
|
||||
assign BIU_REGISTER_RM = biu_register_rm_d2;
|
||||
assign BIU_REGISTER_REG = biu_register_reg_d2;
|
||||
assign BIU_RETURN_DATA = biu_return_data_int_d2;
|
||||
assign BIU_NMI_CAUGHT = nmi_caught;
|
||||
|
||||
|
||||
|
||||
// Input signals from the EU requesting BIU processing.
|
||||
// eu_biu_strobe[1:0] are available for only one clock cycle and cause BIU to take immediate action.
|
||||
// eu_biu_req stays asserted until the BIU is available to service the request.
|
||||
//
|
||||
assign eu_prefix_seg = EU_BIU_COMMAND[14];
|
||||
assign eu_biu_strobe[1:0] = EU_BIU_COMMAND[13:12]; // 01=opcode fetch 10=clock load 11=load segment register(eu_biu_req_code has the regiter#)
|
||||
assign eu_biu_segment[1:0] = EU_BIU_COMMAND[11:10];
|
||||
assign eu_biu_req = EU_BIU_COMMAND[9];
|
||||
assign eu_biu_req_code = EU_BIU_COMMAND[8:4];
|
||||
assign eu_qs_out[1:0] = EU_BIU_COMMAND[3:2]; // Updated for every opcode fetch using biu_strobe and Jump request using eu_biu_rq
|
||||
assign eu_segment_override_value[1:0] = EU_BIU_COMMAND[1:0];
|
||||
|
||||
|
||||
|
||||
// Select either the current EU Segment or the Segment Override value.
|
||||
assign biu_segment = (eu_prefix_seg==1'b1) ? eu_segment_override_value : eu_biu_segment;
|
||||
|
||||
|
||||
assign biu_muxed_segment = (biu_segment==2'b00) ? biu_register_es :
|
||||
(biu_segment==2'b01) ? biu_register_ss :
|
||||
(biu_segment==2'b10) ? biu_register_cs :
|
||||
biu_register_ds ;
|
||||
|
||||
|
||||
// Steer the Prefetch Queue to the EU
|
||||
assign pfq_top_byte_int = (pfq_addr_out[1:0]==2'b00) ? pfq_entry0 :
|
||||
(pfq_addr_out[1:0]==2'b01) ? pfq_entry1 :
|
||||
(pfq_addr_out[1:0]==2'b10) ? pfq_entry2 :
|
||||
pfq_entry3 ;
|
||||
|
||||
assign PFQ_TOP_BYTE = pfq_top_byte_int_d1;
|
||||
|
||||
// Generate the Prefetch Queue Flags
|
||||
assign pfq_full = ( (pfq_addr_in[2]!=pfq_addr_out[2]) && (pfq_addr_in[1:0]==pfq_addr_out[1:0]) ) ? 1'b1 : 1'b0;
|
||||
assign pfq_empty = ( (pfq_addr_in[2]==pfq_addr_out[2]) && (pfq_addr_in[1:0]==pfq_addr_out[1:0]) ) ? 1'b1 : 1'b0;
|
||||
|
||||
|
||||
// Instruction cycle accuracy counter. This can be tied to '1' to disable x86 cycle compatibiliy.
|
||||
assign BIU_CLK_COUNTER_ZERO = (clock_cycle_counter==13'h0000) ? 1'b1 : 1'b0;
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// BIU State Machine
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
always @(posedge CORE_CLK_INT)
|
||||
begin : BIU_STATE_MACHINE
|
||||
|
||||
if (RESET_INT==1'b1)
|
||||
begin
|
||||
clk_d1 <= 'h0;
|
||||
clk_d2 <= 'h0;
|
||||
clk_d3 <= 'h0;
|
||||
clk_d4 <= 'h0;
|
||||
nmi_d1 <= 'h0;
|
||||
nmi_d2 <= 'h0;
|
||||
nmi_d3 <= 'h0;
|
||||
nmi_caught <= 'h0;
|
||||
eu_register_r3_d <= 'h0;
|
||||
eu_biu_req_caught <= 'h0;
|
||||
biu_register_cs <= 16'hFFFF;
|
||||
biu_register_es <= 'h0;
|
||||
biu_register_ss <= 'h0;
|
||||
biu_register_ds <= 'h0;
|
||||
biu_register_rm <= 'h0;
|
||||
biu_register_reg <= 'h0;
|
||||
clock_cycle_counter <= 'h0;
|
||||
pfq_addr_out <= 'h0;
|
||||
pfq_entry0 <= 'h0;
|
||||
pfq_entry1 <= 'h0;
|
||||
pfq_entry2 <= 'h0;
|
||||
pfq_entry3 <= 'h0;
|
||||
biu_state <= 8'hD0;
|
||||
S2_S0_OUT <= 'b111;
|
||||
s2_s0_out_int <= 'b111;
|
||||
pfq_write <= 'h0;
|
||||
pfq_addr_in <= 'h0;
|
||||
biu_lock_n_int <= 1'b1;
|
||||
S6_3_MUX <= 'h0;
|
||||
AD_OE <= 'h0;
|
||||
biu_return_data_int <= 'h0;
|
||||
biu_done_int <= 'h0;
|
||||
ready_d1 <= 'h0;
|
||||
ready_d2 <= 'h0;
|
||||
ready_d3 <= 'h0;
|
||||
eu_biu_req_d1 <= 'h0;
|
||||
latched_data_in <= 'h0;
|
||||
addr_out_temp <= 'h0;
|
||||
s_bits <= 3'b111;
|
||||
AD_OUT <= 'h0;
|
||||
word_cycle <= 1'b0;
|
||||
byte_num <= 1'b0;
|
||||
ad_in_int <= 'h0;
|
||||
BIU_INTR <= 'h0;
|
||||
eu_prefix_lock_d1 <= 'h0;
|
||||
eu_prefix_lock_d2 <= 'h0;
|
||||
LOCK_n <= 1'b1;
|
||||
intr_d1 <= 'h0;
|
||||
intr_d2 <= 'h0;
|
||||
intr_d3 <= 'h0;
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
|
||||
|
||||
// Register pipelining
|
||||
clk_d1 <= CLK;
|
||||
clk_d2 <= clk_d1;
|
||||
clk_d3 <= clk_d2;
|
||||
clk_d4 <= clk_d3;
|
||||
|
||||
ready_d1 <= READY_IN;
|
||||
ready_d2 <= ready_d1;
|
||||
ready_d3 <= ready_d2;
|
||||
|
||||
nmi_d1 <= NMI;
|
||||
nmi_d2 <= nmi_d1;
|
||||
nmi_d3 <= nmi_d2;
|
||||
|
||||
intr_d1 <= INTR;
|
||||
intr_d2 <= intr_d1;
|
||||
intr_d3 <= intr_d2;
|
||||
|
||||
|
||||
// These signals may be pipelined from zero to two clocks.
|
||||
// They are currently pipelined by two clocks.
|
||||
biu_register_es_d1 <= biu_register_es;
|
||||
biu_register_ss_d1 <= biu_register_ss;
|
||||
biu_register_cs_d1 <= biu_register_cs;
|
||||
biu_register_ds_d1 <= biu_register_ds;
|
||||
biu_register_rm_d1 <= biu_register_rm;
|
||||
biu_register_reg_d1 <= biu_register_reg;
|
||||
biu_register_es_d2 <= biu_register_es_d1;
|
||||
biu_register_ss_d2 <= biu_register_ss_d1;
|
||||
biu_register_cs_d2 <= biu_register_cs_d1;
|
||||
biu_register_ds_d2 <= biu_register_ds_d1;
|
||||
biu_register_rm_d2 <= biu_register_rm_d1;
|
||||
biu_register_reg_d2 <= biu_register_reg_d1;
|
||||
|
||||
|
||||
// These signals may be pipelined from zero to one clock.
|
||||
// They are currently pipelined by one clock.
|
||||
pfq_top_byte_int_d1 <= pfq_top_byte_int;
|
||||
pfq_addr_out_d1 <= pfq_addr_out;
|
||||
|
||||
|
||||
// This signal may be pipelined any number of clocks as
|
||||
// long as is stable before BIU_DONE is asserted.
|
||||
biu_return_data_int_d1 <= biu_return_data_int;
|
||||
biu_return_data_int_d2 <= biu_return_data_int_d1;
|
||||
|
||||
|
||||
|
||||
// NMI caught on it's rising edge
|
||||
if (nmi_d3==1'b0 && nmi_d2==1'b0 && nmi_d1==1'b1)
|
||||
begin
|
||||
nmi_caught <= 1'b1;
|
||||
end
|
||||
else if (BIU_NMI_DEBOUNCE==1'b1)
|
||||
begin
|
||||
nmi_caught <= 1'b0;
|
||||
end
|
||||
|
||||
// INTR sampled on the rising edge of the CLK
|
||||
if (clk_d4==1'b0 && clk_d3==1'b0 && clk_d2==1'b1)
|
||||
begin
|
||||
BIU_INTR <= intr_d3;
|
||||
end
|
||||
|
||||
eu_prefix_lock_d1 <= EU_PREFIX_LOCK;
|
||||
eu_prefix_lock_d2 <= eu_prefix_lock_d1;
|
||||
|
||||
// Drive LOCK_n out of the chip only on the falling edge of the 8088 CLK.
|
||||
// LOCK_n can be driven by either the BIU during an INTA cycle or by the
|
||||
// LOCK prefix opcode generated by the EU.
|
||||
if (clk_d3==1'b1 && clk_d2==1'b1 && clk_d1==1'b0)
|
||||
begin
|
||||
LOCK_n <= ~eu_prefix_lock_d2 && biu_lock_n_int;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Register pipelining in and out of the BIU.
|
||||
eu_register_r3_d <= EU_REGISTER_R3;
|
||||
ad_in_int <= AD_IN;
|
||||
S2_S0_OUT <= s2_s0_out_int;
|
||||
|
||||
|
||||
|
||||
// Capture a bus request from the EU
|
||||
eu_biu_req_d1 <= eu_biu_req;
|
||||
if (eu_biu_req_d1==1'b0 && eu_biu_req==1'b1)
|
||||
begin
|
||||
eu_biu_req_caught <= 1'b1;
|
||||
end
|
||||
else if (biu_done_int==1'b1)
|
||||
begin
|
||||
eu_biu_req_caught <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Strobe from EU to update the segment and addressing registers
|
||||
if (eu_biu_strobe==2'b11)
|
||||
begin
|
||||
case (eu_biu_req_code[2:0]) // synthesis parallel_case
|
||||
3'h0 : biu_register_es <= EU_BIU_DATAOUT[15:0];
|
||||
3'h1 : biu_register_ss <= EU_BIU_DATAOUT[15:0];
|
||||
3'h2 : biu_register_cs <= EU_BIU_DATAOUT[15:0];
|
||||
3'h3 : biu_register_ds <= EU_BIU_DATAOUT[15:0];
|
||||
3'h4 : biu_register_rm <= EU_BIU_DATAOUT[15:0];
|
||||
3'h5 : biu_register_reg <= EU_BIU_DATAOUT[15:0];
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
// Strobe from EU to set the 8088 clock cycle counter
|
||||
if (eu_biu_strobe==2'b10)
|
||||
begin
|
||||
clock_cycle_counter <= EU_BIU_DATAOUT[12:0];
|
||||
end
|
||||
else if (clock_cycle_counter!=13'h0000)
|
||||
begin
|
||||
clock_cycle_counter <= clock_cycle_counter - 1;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Prefetch Queue
|
||||
// --------------
|
||||
// Increment the output address of the queue upon EU fetch request strobe.
|
||||
// Update/flush the Prefetch Queue when the EU asserts the Jump request.
|
||||
// Increment the input address during prefetch queue fetches.
|
||||
//---------------------------------------------------------------------------------
|
||||
if (eu_biu_req_caught==1'b1 && eu_biu_req_code==5'h19)
|
||||
begin
|
||||
pfq_addr_out <= eu_register_r3_d; // Update the prefetch queue to the new address.
|
||||
end
|
||||
else if (eu_biu_strobe==2'b01 && pfq_empty==1'b0)
|
||||
begin
|
||||
pfq_addr_out <= pfq_addr_out + 1; // Increment the current IP - Instruction Pointer
|
||||
end
|
||||
|
||||
|
||||
if (eu_biu_req_caught==1'b1 && eu_biu_req_code==5'h19)
|
||||
begin
|
||||
pfq_addr_in <= eu_register_r3_d; // Update the prefetch queue to the new address.
|
||||
end
|
||||
else if (pfq_write==1'b1)
|
||||
begin
|
||||
pfq_addr_in <= pfq_addr_in + 1;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Write to the selected prefetch queue entry.
|
||||
if (pfq_write==1'b1)
|
||||
begin
|
||||
case (pfq_addr_in[1:0]) // synthesis parallel_case
|
||||
2'b00 : pfq_entry0 <= latched_data_in[7:0];
|
||||
2'b01 : pfq_entry1 <= latched_data_in[7:0];
|
||||
2'b10 : pfq_entry2 <= latched_data_in[7:0];
|
||||
2'b11 : pfq_entry3 <= latched_data_in[7:0];
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 8088 BIU State Machine
|
||||
// ----------------------
|
||||
|
||||
biu_state <= biu_state + 1'b1;
|
||||
case (biu_state) // synthesis parallel_case
|
||||
|
||||
8'h00 : begin
|
||||
// Debounce signals
|
||||
pfq_write <= 1'b0;
|
||||
biu_lock_n_int <= 1'b1;
|
||||
S6_3_MUX <= 1'b0;
|
||||
byte_num <= 1'b0;
|
||||
word_cycle <= 1'b0;
|
||||
|
||||
|
||||
if (eu_biu_req_caught==1'b1)
|
||||
begin
|
||||
|
||||
case (eu_biu_req_code) // synthesis parallel_case
|
||||
|
||||
// Interrupt ACK Cycle
|
||||
8'h16 : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
//AD_OE <= 'h0;
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b000;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// IO Byte Read
|
||||
8'h08 : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
s_bits <= 3'b001;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// IO Word Read
|
||||
8'h1A : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b001;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// IO Byte Write
|
||||
8'h0A : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
s_bits <= 3'b010;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// IO Word Write
|
||||
8'h1C : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b010;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Halt Request
|
||||
8'h18 : begin
|
||||
addr_out_temp <= { biu_register_cs[15:0] , 4'h0 } + pfq_addr_out[15:0] ;
|
||||
s_bits <= 3'b011;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Byte Read
|
||||
8'h0C : begin
|
||||
addr_out_temp <= { biu_muxed_segment[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
s_bits <= 3'b101;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Read
|
||||
8'h10 : begin
|
||||
addr_out_temp <= { biu_muxed_segment[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b101;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Read from Stack Segment
|
||||
8'h11 : begin
|
||||
addr_out_temp <= { biu_register_ss[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b101;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Read from Segment 0x0000 - Used for interrupt vector fetches
|
||||
8'h12 : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b101;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Byte Write
|
||||
8'h0E : begin
|
||||
addr_out_temp <= { biu_muxed_segment[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
s_bits <= 3'b110;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Write
|
||||
8'h13 : begin
|
||||
addr_out_temp <= { biu_muxed_segment[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b110;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Write to Stack Segment
|
||||
8'h14 : begin
|
||||
addr_out_temp <= { biu_register_ss[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b110;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Jump Request
|
||||
8'h19 : begin
|
||||
biu_done_int <= 1'b1;
|
||||
biu_state <= 8'h46;
|
||||
end
|
||||
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
else if (pfq_full==1'b0)
|
||||
begin
|
||||
addr_out_temp <= { biu_register_cs[15:0] , 4'h0 } + pfq_addr_in[15:0] ;
|
||||
s_bits <= 3'b100;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
biu_state <= 8'h00;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Wait for the rising edge of CLK to start the bus cycle; then assert the S bits.
|
||||
// Leave AD bus hi-Z during INTA cycles.
|
||||
8'h01 :
|
||||
begin
|
||||
if (s_bits!=3'b000)
|
||||
begin
|
||||
AD_OE <= 1'b1;
|
||||
AD_OUT[19:0] <= addr_out_temp[19:0];
|
||||
end
|
||||
|
||||
S6_3_MUX <= 1'b0;
|
||||
if (clk_d4==1'b0 && clk_d3==1'b0 && clk_d2==1'b1) // Wait until next CLK rising edge
|
||||
begin
|
||||
s2_s0_out_int <= s_bits;
|
||||
end
|
||||
else
|
||||
begin
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
// On the next falling CLK edge, switch the S[6:3] bits mode and float the AD[7:0] bus if it is a read cycle, and mux data to the databus
|
||||
// Assert the LOCK_n signal on the first cycle of an INTA cycle.
|
||||
8'h1A : begin
|
||||
if (s_bits==3'b000 && byte_num==1'b0)
|
||||
begin
|
||||
biu_lock_n_int <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
biu_lock_n_int <= 1'b1;
|
||||
end
|
||||
|
||||
S6_3_MUX <= 1'b1;
|
||||
|
||||
AD_OE <= s_bits[1]; // Turn off bus drivers for read cycles
|
||||
|
||||
if (word_cycle==1'b1 && byte_num==1'b1)
|
||||
begin
|
||||
AD_OUT[7:0] <= EU_BIU_DATAOUT[15:8];
|
||||
end
|
||||
else
|
||||
begin
|
||||
AD_OUT[7:0] <= EU_BIU_DATAOUT[7:0];
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
// On the next falling CLK edge, sample the READY signal
|
||||
8'h36 : begin
|
||||
if (ready_d3==1'b0) // Not ready yet, wait another clock cycle
|
||||
begin
|
||||
biu_state <= 8'h22;
|
||||
end
|
||||
else
|
||||
begin
|
||||
s2_s0_out_int <= 3'b111;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
// On the next rising CLK edge, sample the data.
|
||||
8'h3D : begin
|
||||
latched_data_in <= ad_in_int;
|
||||
|
||||
// If a code fetch, then write data to the prefetch queue
|
||||
if (s_bits==3'b100)
|
||||
begin
|
||||
pfq_write <= 1'b1;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Debounce the prefetch queue write pulse and increment the prefetch queue address.
|
||||
8'h3E : begin
|
||||
pfq_write <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Steer the data
|
||||
8'h40 : begin
|
||||
if (s_bits!=3'b000 && (word_cycle==1'b1 && byte_num==1'b1))
|
||||
begin
|
||||
biu_return_data_int[15:8] <= latched_data_in[7:0];
|
||||
end
|
||||
else
|
||||
begin
|
||||
biu_return_data_int[15:0] <= { 8'h00 , latched_data_in[7:0] };
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
// On the next falling CLK edge, the cycle is complete.
|
||||
8'h45 : begin
|
||||
addr_out_temp[15:0] <= addr_out_temp[15:0] + 1;
|
||||
if (word_cycle==1'b1 && byte_num==1'b0)
|
||||
begin
|
||||
byte_num <= 1'b1;
|
||||
biu_state <= 8'h50;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (s_bits!=3'b100)
|
||||
begin
|
||||
biu_done_int <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
8'h46 : begin
|
||||
biu_done_int <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
8'h4E : begin
|
||||
biu_state <= 8'h00;
|
||||
end
|
||||
|
||||
|
||||
8'h58 : begin
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
|
||||
default : ;
|
||||
endcase
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
end // BIU
|
||||
|
||||
|
||||
endmodule // biu.v
|
||||
|
||||
|
||||
|
||||
|
||||
780
common/CPU/8088/biu_min.v
Normal file
780
common/CPU/8088/biu_min.v
Normal file
@ -0,0 +1,780 @@
|
||||
//
|
||||
//
|
||||
// File Name : biu_min.v
|
||||
// Used on :
|
||||
// Author : Ted Fried, MicroCore Labs
|
||||
// Creation : 10/8/2015
|
||||
// Code Type : Synthesizable
|
||||
//
|
||||
// Description:
|
||||
// ============
|
||||
//
|
||||
// Bus Interface Unit of the i8088 processor in Minimum Bus Mode
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// Modification History:
|
||||
// =====================
|
||||
//
|
||||
// Revision 1.0 10/8/15
|
||||
// Initial revision
|
||||
//
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2020 Ted Fried
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
module biu_min
|
||||
(
|
||||
input CORE_CLK_INT, // Core Clock
|
||||
|
||||
|
||||
input CLK, // 8088 Pins
|
||||
input RESET_INT,
|
||||
input READY_IN,
|
||||
input NMI,
|
||||
input INTR,
|
||||
output reg INTA_n,
|
||||
output reg ALE,
|
||||
output reg RD_n,
|
||||
output reg WR_n,
|
||||
output reg IOM,
|
||||
output reg DTR,
|
||||
output reg DEN,
|
||||
output reg AD_OE,
|
||||
output reg [19:0] AD_OUT,
|
||||
input [7:0] AD_IN,
|
||||
|
||||
|
||||
input [15:0] EU_BIU_COMMAND, // EU to BIU Signals
|
||||
input [15:0] EU_BIU_DATAOUT,
|
||||
input [15:0] EU_REGISTER_R3,
|
||||
input EU_PREFIX_LOCK,
|
||||
|
||||
|
||||
output BIU_DONE, // BIU to EU Signals
|
||||
output BIU_CLK_COUNTER_ZERO,
|
||||
output [1:0] BIU_SEGMENT,
|
||||
output BIU_NMI_CAUGHT,
|
||||
input BIU_NMI_DEBOUNCE,
|
||||
output reg BIU_INTR,
|
||||
|
||||
output [7:0] PFQ_TOP_BYTE,
|
||||
output PFQ_EMPTY,
|
||||
output[15:0] PFQ_ADDR_OUT,
|
||||
|
||||
output [15:0] BIU_REGISTER_ES,
|
||||
output [15:0] BIU_REGISTER_SS,
|
||||
output [15:0] BIU_REGISTER_CS,
|
||||
output [15:0] BIU_REGISTER_DS,
|
||||
output [15:0] BIU_REGISTER_RM,
|
||||
output [15:0] BIU_REGISTER_REG,
|
||||
output [15:0] BIU_RETURN_DATA
|
||||
|
||||
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Internal Signals
|
||||
|
||||
reg biu_done_int;
|
||||
reg byte_num;
|
||||
reg clk_d1;
|
||||
reg clk_d2;
|
||||
reg clk_d3;
|
||||
reg clk_d4;
|
||||
reg eu_biu_req_caught;
|
||||
reg eu_biu_req_d1;
|
||||
reg eu_prefix_lock_d1;
|
||||
reg eu_prefix_lock_d2;
|
||||
reg intr_d1;
|
||||
reg intr_d2;
|
||||
reg intr_d3;
|
||||
reg nmi_caught;
|
||||
reg nmi_d1;
|
||||
reg nmi_d2;
|
||||
reg nmi_d3;
|
||||
reg pfq_write;
|
||||
reg ready_d1;
|
||||
reg ready_d2;
|
||||
reg ready_d3;
|
||||
reg word_cycle;
|
||||
wire eu_biu_req;
|
||||
wire eu_prefix_seg;
|
||||
wire pfq_empty;
|
||||
reg [7:0] ad_in_int;
|
||||
reg [19:0] addr_out_temp;
|
||||
reg [7:0] biu_state;
|
||||
reg [15:0] biu_register_cs;
|
||||
reg [15:0] biu_register_es;
|
||||
reg [15:0] biu_register_ss;
|
||||
reg [15:0] biu_register_ds;
|
||||
reg [15:0] biu_register_rm;
|
||||
reg [15:0] biu_register_reg;
|
||||
reg [15:0] biu_register_cs_d1;
|
||||
reg [15:0] biu_register_es_d1;
|
||||
reg [15:0] biu_register_ss_d1;
|
||||
reg [15:0] biu_register_ds_d1;
|
||||
reg [15:0] biu_register_rm_d1;
|
||||
reg [15:0] biu_register_reg_d1;
|
||||
reg [15:0] biu_register_cs_d2;
|
||||
reg [15:0] biu_register_es_d2;
|
||||
reg [15:0] biu_register_ss_d2;
|
||||
reg [15:0] biu_register_ds_d2;
|
||||
reg [15:0] biu_register_rm_d2;
|
||||
reg [15:0] biu_register_reg_d2;
|
||||
reg [15:0] biu_return_data_int;
|
||||
reg [15:0] biu_return_data_int_d1;
|
||||
reg [15:0] biu_return_data_int_d2;
|
||||
reg [12:0] clock_cycle_counter;
|
||||
reg [15:0] eu_register_r3_d;
|
||||
reg [7:0] latched_data_in;
|
||||
reg [15:0] pfq_addr_out;
|
||||
reg [7:0] pfq_entry0;
|
||||
reg [7:0] pfq_entry1;
|
||||
reg [7:0] pfq_entry2;
|
||||
reg [7:0] pfq_entry3;
|
||||
reg [15:0] pfq_addr_in;
|
||||
reg [7:0] pfq_top_byte_int_d1;
|
||||
reg [15:0] pfq_addr_out_d1;
|
||||
reg [2:0] s_bits;
|
||||
wire [15:0] biu_muxed_segment;
|
||||
wire [1:0] biu_segment;
|
||||
wire [1:0] eu_biu_strobe;
|
||||
wire [1:0] eu_biu_segment;
|
||||
wire [4:0] eu_biu_req_code;
|
||||
wire [1:0] eu_qs_out;
|
||||
wire [1:0] eu_segment_override_value;
|
||||
wire [7:0] pfq_top_byte_int;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// BIU Combinationals
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
// Outputs to the EU
|
||||
//
|
||||
assign BIU_DONE = biu_done_int;
|
||||
assign PFQ_EMPTY = pfq_empty;
|
||||
assign PFQ_ADDR_OUT = pfq_addr_out_d1;
|
||||
assign BIU_SEGMENT = biu_segment;
|
||||
assign BIU_REGISTER_ES = biu_register_es_d2;
|
||||
assign BIU_REGISTER_SS = biu_register_ss_d2;
|
||||
assign BIU_REGISTER_CS = biu_register_cs_d2;
|
||||
assign BIU_REGISTER_DS = biu_register_ds_d2;
|
||||
assign BIU_REGISTER_RM = biu_register_rm_d2;
|
||||
assign BIU_REGISTER_REG = biu_register_reg_d2;
|
||||
assign BIU_RETURN_DATA = biu_return_data_int_d2;
|
||||
assign BIU_NMI_CAUGHT = nmi_caught;
|
||||
|
||||
|
||||
|
||||
// Input signals from the EU requesting BIU processing.
|
||||
// eu_biu_strobe[1:0] are available for only one clock cycle and cause BIU to take immediate action.
|
||||
// eu_biu_req stays asserted until the BIU is available to service the request.
|
||||
//
|
||||
assign eu_prefix_seg = EU_BIU_COMMAND[14];
|
||||
assign eu_biu_strobe[1:0] = EU_BIU_COMMAND[13:12]; // 01=opcode fetch 10=clock load 11=load segment register(eu_biu_req_code has the regiter#)
|
||||
assign eu_biu_segment[1:0] = EU_BIU_COMMAND[11:10];
|
||||
assign eu_biu_req = EU_BIU_COMMAND[9];
|
||||
assign eu_biu_req_code = EU_BIU_COMMAND[8:4];
|
||||
assign eu_qs_out[1:0] = EU_BIU_COMMAND[3:2]; // Updated for every opcode fetch using biu_strobe and Jump request using eu_biu_rq
|
||||
assign eu_segment_override_value[1:0] = EU_BIU_COMMAND[1:0];
|
||||
|
||||
|
||||
|
||||
// Select either the current EU Segment or the Segment Override value.
|
||||
assign biu_segment = (eu_prefix_seg==1'b1) ? eu_segment_override_value : eu_biu_segment;
|
||||
|
||||
|
||||
assign biu_muxed_segment = (biu_segment==2'b00) ? biu_register_es :
|
||||
(biu_segment==2'b01) ? biu_register_ss :
|
||||
(biu_segment==2'b10) ? biu_register_cs :
|
||||
biu_register_ds ;
|
||||
|
||||
|
||||
// Steer the Prefetch Queue to the EU
|
||||
assign pfq_top_byte_int = (pfq_addr_out[1:0]==2'b00) ? pfq_entry0 :
|
||||
(pfq_addr_out[1:0]==2'b01) ? pfq_entry1 :
|
||||
(pfq_addr_out[1:0]==2'b10) ? pfq_entry2 :
|
||||
pfq_entry3 ;
|
||||
|
||||
assign PFQ_TOP_BYTE = pfq_top_byte_int_d1;
|
||||
|
||||
// Generate the Prefetch Queue Flags
|
||||
assign pfq_full = ( (pfq_addr_in[2]!=pfq_addr_out[2]) && (pfq_addr_in[1:0]==pfq_addr_out[1:0]) ) ? 1'b1 : 1'b0;
|
||||
assign pfq_empty = ( (pfq_addr_in[2]==pfq_addr_out[2]) && (pfq_addr_in[1:0]==pfq_addr_out[1:0]) ) ? 1'b1 : 1'b0;
|
||||
|
||||
|
||||
// Instruction cycle accuracy counter. This can be tied to '1' to disable x86 cycle compatibiliy.
|
||||
assign BIU_CLK_COUNTER_ZERO = (clock_cycle_counter==13'h0000) ? 1'b1 : 1'b0;
|
||||
//assign BIU_CLK_COUNTER_ZERO = 1'b1;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// BIU State Machine
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
always @(posedge CORE_CLK_INT)
|
||||
begin : BIU_STATE_MACHINE
|
||||
|
||||
if (RESET_INT==1'b1)
|
||||
begin
|
||||
clk_d1 <= 'h0;
|
||||
clk_d2 <= 'h0;
|
||||
clk_d3 <= 'h0;
|
||||
clk_d4 <= 'h0;
|
||||
nmi_d1 <= 'h0;
|
||||
nmi_d2 <= 'h0;
|
||||
nmi_d3 <= 'h0;
|
||||
nmi_caught <= 'h0;
|
||||
eu_register_r3_d <= 'h0;
|
||||
eu_biu_req_caught <= 'h0;
|
||||
biu_register_cs <= 16'hFFFF;
|
||||
biu_register_es <= 'h0;
|
||||
biu_register_ss <= 'h0;
|
||||
biu_register_ds <= 'h0;
|
||||
biu_register_rm <= 'h0;
|
||||
biu_register_reg <= 'h0;
|
||||
clock_cycle_counter <= 'h0;
|
||||
pfq_addr_out <= 'h0;
|
||||
pfq_entry0 <= 'h0;
|
||||
pfq_entry1 <= 'h0;
|
||||
pfq_entry2 <= 'h0;
|
||||
pfq_entry3 <= 'h0;
|
||||
biu_state <= 8'hD0;
|
||||
pfq_write <= 'h0;
|
||||
pfq_addr_in <= 'h0;
|
||||
biu_return_data_int <= 'h0;
|
||||
biu_done_int <= 'h0;
|
||||
ready_d1 <= 'h0;
|
||||
ready_d2 <= 'h0;
|
||||
ready_d3 <= 'h0;
|
||||
eu_biu_req_d1 <= 'h0;
|
||||
latched_data_in <= 'h0;
|
||||
addr_out_temp <= 'h0;
|
||||
s_bits <= 3'b111;
|
||||
AD_OUT <= 'h0;
|
||||
word_cycle <= 1'b0;
|
||||
byte_num <= 1'b0;
|
||||
ad_in_int <= 'h0;
|
||||
BIU_INTR <= 'h0;
|
||||
eu_prefix_lock_d1 <= 'h0;
|
||||
eu_prefix_lock_d2 <= 'h0;
|
||||
intr_d1 <= 'h0;
|
||||
intr_d2 <= 'h0;
|
||||
intr_d3 <= 'h0;
|
||||
|
||||
AD_OE <= 'h0;
|
||||
RD_n <= 1'b1;
|
||||
WR_n <= 1'b1;
|
||||
IOM <= 'h0;
|
||||
DTR <= 'h0;
|
||||
DEN <= 1'b1;
|
||||
INTA_n <= 1'b1;
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
|
||||
|
||||
// Register pipelining
|
||||
clk_d1 <= CLK;
|
||||
clk_d2 <= clk_d1;
|
||||
clk_d3 <= clk_d2;
|
||||
clk_d4 <= clk_d3;
|
||||
|
||||
ready_d1 <= READY_IN;
|
||||
ready_d2 <= ready_d1;
|
||||
ready_d3 <= ready_d2;
|
||||
|
||||
nmi_d1 <= NMI;
|
||||
nmi_d2 <= nmi_d1;
|
||||
nmi_d3 <= nmi_d2;
|
||||
|
||||
intr_d1 <= INTR;
|
||||
intr_d2 <= intr_d1;
|
||||
intr_d3 <= intr_d2;
|
||||
|
||||
|
||||
// These signals may be pipelined from zero to two clocks.
|
||||
// They are currently pipelined by two clocks.
|
||||
biu_register_es_d1 <= biu_register_es;
|
||||
biu_register_ss_d1 <= biu_register_ss;
|
||||
biu_register_cs_d1 <= biu_register_cs;
|
||||
biu_register_ds_d1 <= biu_register_ds;
|
||||
biu_register_rm_d1 <= biu_register_rm;
|
||||
biu_register_reg_d1 <= biu_register_reg;
|
||||
biu_register_es_d2 <= biu_register_es_d1;
|
||||
biu_register_ss_d2 <= biu_register_ss_d1;
|
||||
biu_register_cs_d2 <= biu_register_cs_d1;
|
||||
biu_register_ds_d2 <= biu_register_ds_d1;
|
||||
biu_register_rm_d2 <= biu_register_rm_d1;
|
||||
biu_register_reg_d2 <= biu_register_reg_d1;
|
||||
|
||||
|
||||
// These signals may be pipelined from zero to one clock.
|
||||
// They are currently pipelined by one clock.
|
||||
pfq_top_byte_int_d1 <= pfq_top_byte_int;
|
||||
pfq_addr_out_d1 <= pfq_addr_out;
|
||||
|
||||
|
||||
// This signal may be pipelined any number of clocks as
|
||||
// long as is stable before BIU_DONE is asserted.
|
||||
biu_return_data_int_d1 <= biu_return_data_int;
|
||||
biu_return_data_int_d2 <= biu_return_data_int_d1;
|
||||
|
||||
|
||||
|
||||
// NMI caught on it's rising edge
|
||||
if (nmi_d3==1'b0 && nmi_d2==1'b0 && nmi_d1==1'b1)
|
||||
begin
|
||||
nmi_caught <= 1'b1;
|
||||
end
|
||||
else if (BIU_NMI_DEBOUNCE==1'b1)
|
||||
begin
|
||||
nmi_caught <= 1'b0;
|
||||
end
|
||||
|
||||
// INTR sampled on the rising edge of the CLK
|
||||
if (clk_d4==1'b0 && clk_d3==1'b0 && clk_d2==1'b1)
|
||||
begin
|
||||
BIU_INTR <= intr_d3;
|
||||
end
|
||||
|
||||
eu_prefix_lock_d1 <= EU_PREFIX_LOCK;
|
||||
eu_prefix_lock_d2 <= eu_prefix_lock_d1;
|
||||
|
||||
|
||||
// Register pipelining in and out of the BIU.
|
||||
eu_register_r3_d <= EU_REGISTER_R3;
|
||||
ad_in_int <= AD_IN;
|
||||
|
||||
|
||||
|
||||
// Capture a bus request from the EU
|
||||
eu_biu_req_d1 <= eu_biu_req;
|
||||
if (eu_biu_req_d1==1'b0 && eu_biu_req==1'b1)
|
||||
begin
|
||||
eu_biu_req_caught <= 1'b1;
|
||||
end
|
||||
else if (biu_done_int==1'b1)
|
||||
begin
|
||||
eu_biu_req_caught <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Strobe from EU to update the segment and addressing registers
|
||||
if (eu_biu_strobe==2'b11)
|
||||
begin
|
||||
case (eu_biu_req_code[2:0]) // synthesis parallel_case
|
||||
3'h0 : biu_register_es <= EU_BIU_DATAOUT[15:0];
|
||||
3'h1 : biu_register_ss <= EU_BIU_DATAOUT[15:0];
|
||||
3'h2 : biu_register_cs <= EU_BIU_DATAOUT[15:0];
|
||||
3'h3 : biu_register_ds <= EU_BIU_DATAOUT[15:0];
|
||||
3'h4 : biu_register_rm <= EU_BIU_DATAOUT[15:0];
|
||||
3'h5 : biu_register_reg <= EU_BIU_DATAOUT[15:0];
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
// Strobe from EU to set the 8088 clock cycle counter
|
||||
if (eu_biu_strobe==2'b10)
|
||||
begin
|
||||
clock_cycle_counter <= EU_BIU_DATAOUT[12:0];
|
||||
end
|
||||
else if (clock_cycle_counter!=13'h0000)
|
||||
begin
|
||||
clock_cycle_counter <= clock_cycle_counter - 1;
|
||||
end
|
||||
|
||||
|
||||
// Prefetch Queue
|
||||
// --------------
|
||||
// Increment the output address of the queue upon EU fetch request strobe.
|
||||
// Update/flush the Prefetch Queue when the EU asserts the Jump request.
|
||||
// Increment the input address during prefetch queue fetches.
|
||||
//---------------------------------------------------------------------------------
|
||||
if (eu_biu_req_caught==1'b1 && eu_biu_req_code==5'h19)
|
||||
begin
|
||||
pfq_addr_out <= eu_register_r3_d; // Update the prefetch queue to the new address.
|
||||
end
|
||||
else if (eu_biu_strobe==2'b01 && pfq_empty==1'b0)
|
||||
begin
|
||||
pfq_addr_out <= pfq_addr_out + 1; // Increment the current IP - Instruction Pointer
|
||||
end
|
||||
|
||||
|
||||
if (eu_biu_req_caught==1'b1 && eu_biu_req_code==5'h19)
|
||||
begin
|
||||
pfq_addr_in <= eu_register_r3_d; // Update the prefetch queue to the new address.
|
||||
end
|
||||
else if (pfq_write==1'b1)
|
||||
begin
|
||||
pfq_addr_in <= pfq_addr_in + 1;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Write to the selected prefetch queue entry.
|
||||
if (pfq_write==1'b1)
|
||||
begin
|
||||
case (pfq_addr_in[1:0]) // synthesis parallel_case
|
||||
2'b00 : pfq_entry0 <= latched_data_in[7:0];
|
||||
2'b01 : pfq_entry1 <= latched_data_in[7:0];
|
||||
2'b10 : pfq_entry2 <= latched_data_in[7:0];
|
||||
2'b11 : pfq_entry3 <= latched_data_in[7:0];
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 8088 BIU State Machine
|
||||
// ----------------------
|
||||
|
||||
biu_state <= biu_state + 1'b1;
|
||||
case (biu_state) // synthesis parallel_case
|
||||
|
||||
8'h00 : begin
|
||||
// Debounce signals
|
||||
pfq_write <= 1'b0;
|
||||
byte_num <= 1'b0;
|
||||
word_cycle <= 1'b0;
|
||||
|
||||
|
||||
if (eu_biu_req_caught==1'b1)
|
||||
begin
|
||||
|
||||
case (eu_biu_req_code) // synthesis parallel_case
|
||||
|
||||
// Interrupt ACK Cycle
|
||||
8'h16 : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
//AD_OE <= 'h0;
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b000;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// IO Byte Read
|
||||
8'h08 : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
s_bits <= 3'b001;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// IO Word Read
|
||||
8'h1A : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b001;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// IO Byte Write
|
||||
8'h0A : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
s_bits <= 3'b010;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// IO Word Write
|
||||
8'h1C : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b010;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Halt Request
|
||||
8'h18 : begin
|
||||
addr_out_temp <= { biu_register_cs[15:0] , 4'h0 } + pfq_addr_out[15:0] ;
|
||||
s_bits <= 3'b011;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Byte Read
|
||||
8'h0C : begin
|
||||
addr_out_temp <= { biu_muxed_segment[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
s_bits <= 3'b101;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Read
|
||||
8'h10 : begin
|
||||
addr_out_temp <= { biu_muxed_segment[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b101;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Read from Stack Segment
|
||||
8'h11 : begin
|
||||
addr_out_temp <= { biu_register_ss[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b101;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Read from Segment 0x0000 - Used for interrupt vector fetches
|
||||
8'h12 : begin
|
||||
addr_out_temp <= { 4'h0 , eu_register_r3_d[15:0] };
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b101;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Byte Write
|
||||
8'h0E : begin
|
||||
addr_out_temp <= { biu_muxed_segment[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
s_bits <= 3'b110;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Write
|
||||
8'h13 : begin
|
||||
addr_out_temp <= { biu_muxed_segment[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b110;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Memory Word Write to Stack Segment
|
||||
8'h14 : begin
|
||||
addr_out_temp <= { biu_register_ss[15:0] , 4'h0 } + eu_register_r3_d[15:0];
|
||||
word_cycle <= 1'b1;
|
||||
s_bits <= 3'b110;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
// Jump Request
|
||||
8'h19 : begin
|
||||
biu_done_int <= 1'b1;
|
||||
biu_state <= 8'h46;
|
||||
end
|
||||
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
else if (pfq_full==1'b0)
|
||||
begin
|
||||
addr_out_temp <= { biu_register_cs[15:0] , 4'h0 } + pfq_addr_in[15:0] ;
|
||||
s_bits <= 3'b100;
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
biu_state <= 8'h00;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
// 1 Wait for the rising edge of CLK to start the bus cycle; then assert IOM and DTR
|
||||
8'h01 :
|
||||
begin
|
||||
if (clk_d4==1'b0 && clk_d3==1'b0 && clk_d2==1'b1) // Wait until next CLK rising edge
|
||||
begin
|
||||
IOM <= ~s_bits[2]; // Memory cycles
|
||||
DTR <= s_bits[1]; // Read cycles
|
||||
end
|
||||
else
|
||||
begin
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
// 2 On the next falling CLK edge, assert the ALE and the address
|
||||
8'h04 : begin
|
||||
AD_OUT[19:0] <= addr_out_temp[19:0];
|
||||
AD_OE <= 1'b1;
|
||||
ALE <= 1'b1;
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
// 3 On the next rising CLK edge, disable ALE, drive early DEN
|
||||
8'h13 : begin
|
||||
ALE <= 1'b0;
|
||||
|
||||
if (s_bits[1]==1'b1)
|
||||
begin
|
||||
DEN <= 1'b0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
// 4 On the next falling CLK edge, float the AD[7:0] bus if it is a read cycle, and drive AD with write data
|
||||
8'h19 : begin
|
||||
AD_OE <= s_bits[1]; // Turn off bus drivers for read cycles
|
||||
RD_n <= s_bits[1]; // Assert RD_n for read cycles
|
||||
WR_n <= ~s_bits[1]; // Assert WR_n for write cycles
|
||||
|
||||
if (s_bits==3'b000)
|
||||
begin
|
||||
INTA_n <= 1'b0;
|
||||
end
|
||||
|
||||
if (word_cycle==1'b1 && byte_num==1'b1)
|
||||
begin
|
||||
AD_OUT[7:0] <= EU_BIU_DATAOUT[15:8];
|
||||
end
|
||||
else
|
||||
begin
|
||||
AD_OUT[7:0] <= EU_BIU_DATAOUT[7:0];
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
// 5 On the next rising CLK edge, assert DEN is if has not been already
|
||||
8'h28 : begin
|
||||
DEN <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
// 6 On the next falling CLK edge, sample the READY signal
|
||||
8'h2F : begin
|
||||
if (ready_d3==1'b0) // Not ready yet, wait another clock cycle
|
||||
begin
|
||||
biu_state <= 8'h1A;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
// 7 On the next rising CLK edge, sample the data.
|
||||
8'h3D : begin
|
||||
latched_data_in <= ad_in_int;
|
||||
|
||||
// If a code fetch, then write data to the prefetch queue
|
||||
if (s_bits==3'b100)
|
||||
begin
|
||||
pfq_write <= 1'b1;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
// Debounce the prefetch queue write pulse and increment the prefetch queue address.
|
||||
8'h3E : begin
|
||||
pfq_write <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// 8 Steer the data
|
||||
8'h40 : begin
|
||||
if (s_bits!=3'b000 && (word_cycle==1'b1 && byte_num==1'b1))
|
||||
begin
|
||||
biu_return_data_int[15:8] <= latched_data_in[7:0];
|
||||
end
|
||||
else
|
||||
begin
|
||||
biu_return_data_int[15:0] <= { 8'h00 , latched_data_in[7:0] };
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
// 8 On the next falling CLK edge, the cycle is complete.
|
||||
8'h45 : begin
|
||||
WR_n <= 1'b1;
|
||||
RD_n <= 1'b1;
|
||||
DEN <= 1'b1;
|
||||
INTA_n <= 1'b1;
|
||||
|
||||
|
||||
addr_out_temp[15:0] <= addr_out_temp[15:0] + 1;
|
||||
if (word_cycle==1'b1 && byte_num==1'b0)
|
||||
begin
|
||||
byte_num <= 1'b1;
|
||||
biu_state <= 8'h50;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (s_bits!=3'b100)
|
||||
begin
|
||||
biu_done_int <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
8'h46 : begin
|
||||
biu_done_int <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
8'h4E : begin
|
||||
biu_state <= 8'h00;
|
||||
end
|
||||
|
||||
|
||||
8'h58 : begin
|
||||
biu_state <= 8'h01;
|
||||
end
|
||||
|
||||
|
||||
default : ;
|
||||
endcase
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
end // BIU
|
||||
|
||||
|
||||
endmodule // biu.v
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
15
common/CPU/8088/eu_rom.v
Normal file
15
common/CPU/8088/eu_rom.v
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
module eu_rom(
|
||||
input clka,
|
||||
input [11:0] addra,
|
||||
output reg [31:0] douta
|
||||
);
|
||||
|
||||
reg [31:0] memory[3961:0];
|
||||
|
||||
initial $readmemb("microcode.mem", memory);
|
||||
|
||||
always @(posedge clka)
|
||||
douta <= memory[addra];
|
||||
|
||||
endmodule
|
||||
152
common/CPU/8088/i8088.v
Normal file
152
common/CPU/8088/i8088.v
Normal file
@ -0,0 +1,152 @@
|
||||
|
||||
module i8088
|
||||
(
|
||||
input CORE_CLK,
|
||||
|
||||
input CLK,
|
||||
input RESET,
|
||||
|
||||
input READY,
|
||||
input INTR,
|
||||
input NMI,
|
||||
|
||||
output reg [19:0] addr,
|
||||
output reg [7:0] dout,
|
||||
input [7:0] din,
|
||||
|
||||
output ALE,
|
||||
output INTA_n,
|
||||
output RD_n,
|
||||
output WR_n,
|
||||
output IOM,
|
||||
output DTR,
|
||||
output DEN
|
||||
// output SSO_n
|
||||
|
||||
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// Internal Signals
|
||||
|
||||
reg t_biu_lock_n_d;
|
||||
wire t_eu_prefix_lock;
|
||||
wire t_eu_flag_i;
|
||||
wire t_biu_lock_n;
|
||||
wire t_pfq_empty;
|
||||
wire t_biu_done;
|
||||
wire t_biu_clk_counter_zero;
|
||||
wire t_biu_ad_oe;
|
||||
wire t_biu_nmi_caught;
|
||||
wire t_biu_nmi_debounce;
|
||||
wire t_sram_d_oe;
|
||||
wire t_biu_intr;
|
||||
wire [19:0] t_biu_ad_out;
|
||||
wire [7:0] t_biu_ad_in;
|
||||
wire [2:0] t_s2_s0_out;
|
||||
wire [15:0] t_eu_biu_command;
|
||||
wire [15:0] t_eu_biu_dataout;
|
||||
wire [15:0] t_eu_register_r3;
|
||||
wire [7:0] t_pfq_top_byte;
|
||||
wire [15:0] t_pfq_addr_out;
|
||||
wire [15:0] t_biu_register_es;
|
||||
wire [15:0] t_biu_register_ss;
|
||||
wire [15:0] t_biu_register_cs;
|
||||
wire [15:0] t_biu_register_ds;
|
||||
wire [15:0] t_biu_register_rm;
|
||||
wire [15:0] t_biu_register_reg;
|
||||
wire [15:0] t_biu_return_data;
|
||||
|
||||
always @(posedge CORE_CLK) begin
|
||||
|
||||
if (ALE == 1'b0)
|
||||
dout <= t_biu_ad_out[7:0];
|
||||
else
|
||||
addr <= t_biu_ad_out;
|
||||
|
||||
end
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// BIU Core
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
biu_min BIU_CORE
|
||||
(
|
||||
.CORE_CLK_INT (CORE_CLK),
|
||||
.RESET_INT (RESET),
|
||||
.CLK (CLK),
|
||||
.READY_IN (READY),
|
||||
.NMI (NMI),
|
||||
.INTR (INTR),
|
||||
.INTA_n (INTA_n),
|
||||
.ALE (ALE),
|
||||
.RD_n (RD_n),
|
||||
.WR_n (WR_n),
|
||||
.IOM (IOM),
|
||||
.DTR (DTR),
|
||||
.DEN (DEN),
|
||||
.AD_OE (t_biu_ad_oe),
|
||||
.AD_OUT (t_biu_ad_out),
|
||||
.AD_IN (din),
|
||||
.EU_BIU_COMMAND (t_eu_biu_command),
|
||||
.EU_BIU_DATAOUT (t_eu_biu_dataout),
|
||||
.EU_REGISTER_R3 (t_eu_register_r3),
|
||||
.EU_PREFIX_LOCK (t_eu_prefix_lock),
|
||||
.BIU_DONE (t_biu_done),
|
||||
.BIU_CLK_COUNTER_ZERO (t_biu_clk_counter_zero),
|
||||
.BIU_SEGMENT ( ),
|
||||
.BIU_NMI_CAUGHT (t_biu_nmi_caught),
|
||||
.BIU_NMI_DEBOUNCE (t_biu_nmi_debounce),
|
||||
.BIU_INTR (t_biu_intr),
|
||||
.PFQ_TOP_BYTE (t_pfq_top_byte),
|
||||
.PFQ_EMPTY (t_pfq_empty),
|
||||
.PFQ_ADDR_OUT (t_pfq_addr_out),
|
||||
.BIU_REGISTER_ES (t_biu_register_es),
|
||||
.BIU_REGISTER_SS (t_biu_register_ss),
|
||||
.BIU_REGISTER_CS (t_biu_register_cs),
|
||||
.BIU_REGISTER_DS (t_biu_register_ds),
|
||||
.BIU_REGISTER_RM (t_biu_register_rm),
|
||||
.BIU_REGISTER_REG (t_biu_register_reg),
|
||||
.BIU_RETURN_DATA (t_biu_return_data)
|
||||
|
||||
);
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// EU Core
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
mcl86_eu_core EU_CORE
|
||||
(
|
||||
.CORE_CLK_INT (CORE_CLK),
|
||||
.RESET_INT (RESET),
|
||||
.TEST_N_INT (1'b1),
|
||||
.EU_BIU_COMMAND (t_eu_biu_command),
|
||||
.EU_BIU_DATAOUT (t_eu_biu_dataout),
|
||||
.EU_REGISTER_R3 (t_eu_register_r3),
|
||||
.EU_PREFIX_LOCK (t_eu_prefix_lock),
|
||||
.EU_FLAG_I (t_eu_flag_i),
|
||||
.BIU_DONE (t_biu_done),
|
||||
.BIU_CLK_COUNTER_ZERO (t_biu_clk_counter_zero),
|
||||
.BIU_NMI_CAUGHT (t_biu_nmi_caught),
|
||||
.BIU_NMI_DEBOUNCE (t_biu_nmi_debounce),
|
||||
.BIU_INTR (t_biu_intr),
|
||||
.PFQ_TOP_BYTE (t_pfq_top_byte),
|
||||
.PFQ_EMPTY (t_pfq_empty),
|
||||
.PFQ_ADDR_OUT (t_pfq_addr_out),
|
||||
.BIU_REGISTER_ES (t_biu_register_es),
|
||||
.BIU_REGISTER_SS (t_biu_register_ss),
|
||||
.BIU_REGISTER_CS (t_biu_register_cs),
|
||||
.BIU_REGISTER_DS (t_biu_register_ds),
|
||||
.BIU_REGISTER_RM (t_biu_register_rm),
|
||||
.BIU_REGISTER_REG (t_biu_register_reg),
|
||||
.BIU_RETURN_DATA (t_biu_return_data)
|
||||
);
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
492
common/CPU/8088/mcl86_eu_core.v
Normal file
492
common/CPU/8088/mcl86_eu_core.v
Normal file
@ -0,0 +1,492 @@
|
||||
//
|
||||
//
|
||||
// File Name : mcl86_eu_core.v
|
||||
// Used on :
|
||||
// Author : Ted Fried, MicroCore Labs
|
||||
// Creation : 10/8/2015
|
||||
// Code Type : Synthesizable
|
||||
//
|
||||
// Description:
|
||||
// ============
|
||||
//
|
||||
// Execution Unit of the i8088 processor - Microsequencer
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// Modification History:
|
||||
// =====================
|
||||
//
|
||||
// Revision 1.0 10/8/15
|
||||
// Initial revision
|
||||
//
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2020 Ted Fried
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
module mcl86_eu_core
|
||||
(
|
||||
input CORE_CLK_INT, // Core Clock
|
||||
input RESET_INT, // Pipelined 8088 RESET pin
|
||||
input TEST_N_INT, // Pipelined 8088 TEST_n pin
|
||||
|
||||
|
||||
output [15:0] EU_BIU_COMMAND, // EU to BIU Signals
|
||||
output [15:0] EU_BIU_DATAOUT,
|
||||
output [15:0] EU_REGISTER_R3,
|
||||
output EU_PREFIX_LOCK,
|
||||
output EU_FLAG_I,
|
||||
|
||||
|
||||
input BIU_DONE, // BIU to EU Signals
|
||||
input BIU_CLK_COUNTER_ZERO,
|
||||
input BIU_NMI_CAUGHT,
|
||||
output BIU_NMI_DEBOUNCE,
|
||||
input BIU_INTR,
|
||||
|
||||
|
||||
input [7:0] PFQ_TOP_BYTE,
|
||||
input PFQ_EMPTY,
|
||||
input[15:0] PFQ_ADDR_OUT,
|
||||
|
||||
|
||||
input [15:0] BIU_REGISTER_ES,
|
||||
input [15:0] BIU_REGISTER_SS,
|
||||
input [15:0] BIU_REGISTER_CS,
|
||||
input [15:0] BIU_REGISTER_DS,
|
||||
input [15:0] BIU_REGISTER_RM,
|
||||
input [15:0] BIU_REGISTER_REG,
|
||||
input [15:0] BIU_RETURN_DATA
|
||||
|
||||
);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Internal Signals
|
||||
|
||||
reg eu_add_carry;
|
||||
reg eu_add_carry8;
|
||||
reg eu_add_aux_carry;
|
||||
reg eu_add_overflow16;
|
||||
reg eu_add_overflow8;
|
||||
reg eu_stall_pipeline;
|
||||
reg eu_flag_t_d;
|
||||
reg biu_done_d1;
|
||||
reg biu_done_d2;
|
||||
reg eu_tr_latched;
|
||||
reg biu_done_caught;
|
||||
reg eu_biu_req_d1;
|
||||
reg intr_enable_delayed;
|
||||
wire eu_prefix_rep;
|
||||
wire eu_prefix_repnz;
|
||||
wire eu_tf_debounce;
|
||||
wire eu_prefix_lock ;
|
||||
wire eu_biu_req;
|
||||
wire eu_parity;
|
||||
wire eu_flag_o;
|
||||
wire eu_flag_d;
|
||||
wire eu_flag_i;
|
||||
wire eu_flag_t;
|
||||
wire eu_flag_s;
|
||||
wire eu_flag_z;
|
||||
wire eu_flag_a;
|
||||
wire eu_flag_p;
|
||||
wire eu_flag_c;
|
||||
wire eu_opcode_jump_call;
|
||||
wire intr_asserted;
|
||||
wire eu_jump_boolean;
|
||||
reg [12:0] eu_rom_address;
|
||||
reg [51:0] eu_calling_address;
|
||||
reg [15:0] eu_register_ax;
|
||||
reg [15:0] eu_register_bx;
|
||||
reg [15:0] eu_register_cx;
|
||||
reg [15:0] eu_register_dx;
|
||||
reg [15:0] eu_register_sp;
|
||||
reg [15:0] eu_register_bp;
|
||||
reg [15:0] eu_register_si;
|
||||
reg [15:0] eu_register_di;
|
||||
reg [15:0] eu_flags;
|
||||
reg [15:0] eu_register_r0;
|
||||
reg [15:0] eu_register_r1;
|
||||
reg [15:0] eu_register_r2;
|
||||
reg [15:0] eu_register_r3;
|
||||
reg [15:0] eu_biu_command;
|
||||
reg [15:0] eu_biu_dataout;
|
||||
reg [15:0] eu_alu_last_result;
|
||||
wire [15:0] adder_out;
|
||||
wire [16:0] carry;
|
||||
wire [2:0] eu_opcode_type;
|
||||
wire [3:0] eu_opcode_dst_sel;
|
||||
wire [3:0] eu_opcode_op0_sel;
|
||||
wire [3:0] eu_opcode_op1_sel;
|
||||
wire [15:0] eu_opcode_immediate;
|
||||
wire [2:0] eu_opcode_jump_src;
|
||||
wire [3:0] eu_opcode_jump_cond;
|
||||
wire [15:0] system_signals;
|
||||
wire [15:0] eu_alu2;
|
||||
wire [15:0] eu_alu3;
|
||||
wire [15:0] eu_alu4;
|
||||
wire [15:0] eu_alu5;
|
||||
wire [15:0] eu_alu6;
|
||||
wire [15:0] eu_alu7;
|
||||
wire [15:0] eu_alu_out;
|
||||
wire [15:0] eu_operand0;
|
||||
wire [15:0] eu_operand1;
|
||||
wire [31:0] eu_rom_data;
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// EU Microcode RAM. 4Kx32 DPRAM
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
eu_rom EU_4Kx32 (
|
||||
|
||||
.clka (CORE_CLK_INT),
|
||||
.addra (eu_rom_address[11:0]),
|
||||
.douta (eu_rom_data)
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// Combinationals
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
assign EU_BIU_COMMAND = eu_biu_command;
|
||||
assign EU_BIU_DATAOUT = eu_biu_dataout;
|
||||
assign EU_REGISTER_R3 = eu_register_r3;
|
||||
assign EU_FLAG_I = intr_enable_delayed;
|
||||
assign EU_PREFIX_LOCK = eu_prefix_lock;
|
||||
|
||||
|
||||
// EU ROM opcode decoder
|
||||
assign eu_opcode_type = eu_rom_data[30:28];
|
||||
assign eu_opcode_dst_sel = eu_rom_data[27:24];
|
||||
assign eu_opcode_op0_sel = eu_rom_data[23:20];
|
||||
assign eu_opcode_op1_sel = eu_rom_data[19:16];
|
||||
assign eu_opcode_immediate = eu_rom_data[15:0];
|
||||
|
||||
assign eu_opcode_jump_call = eu_rom_data[24];
|
||||
assign eu_opcode_jump_src = eu_rom_data[22:20];
|
||||
assign eu_opcode_jump_cond = eu_rom_data[19:16];
|
||||
|
||||
|
||||
|
||||
assign eu_operand0 = (eu_opcode_op0_sel==4'h0) ? eu_register_ax :
|
||||
(eu_opcode_op0_sel==4'h1) ? eu_register_bx :
|
||||
(eu_opcode_op0_sel==4'h2) ? eu_register_cx :
|
||||
(eu_opcode_op0_sel==4'h3) ? eu_register_dx :
|
||||
(eu_opcode_op0_sel==4'h4) ? eu_register_sp :
|
||||
(eu_opcode_op0_sel==4'h5) ? eu_register_bp :
|
||||
(eu_opcode_op0_sel==4'h6) ? eu_register_si :
|
||||
(eu_opcode_op0_sel==4'h7) ? eu_register_di :
|
||||
(eu_opcode_op0_sel==4'h8) ? eu_flags :
|
||||
(eu_opcode_op0_sel==4'h9) ? eu_register_r0 :
|
||||
(eu_opcode_op0_sel==4'hA) ? eu_register_r1 :
|
||||
(eu_opcode_op0_sel==4'hB) ? eu_register_r2 :
|
||||
(eu_opcode_op0_sel==4'hC) ? eu_register_r3 :
|
||||
(eu_opcode_op0_sel==4'hD) ? eu_biu_command :
|
||||
(eu_opcode_op0_sel==4'hE) ? system_signals :
|
||||
16'h0 ;
|
||||
|
||||
|
||||
assign eu_operand1 = (eu_opcode_op1_sel==4'h0) ? BIU_REGISTER_ES :
|
||||
(eu_opcode_op1_sel==4'h1) ? BIU_REGISTER_SS :
|
||||
(eu_opcode_op1_sel==4'h2) ? BIU_REGISTER_CS :
|
||||
(eu_opcode_op1_sel==4'h3) ? BIU_REGISTER_DS :
|
||||
(eu_opcode_op1_sel==4'h4) ? { 8'h00 , PFQ_TOP_BYTE } :
|
||||
(eu_opcode_op1_sel==4'h5) ? BIU_REGISTER_RM :
|
||||
(eu_opcode_op1_sel==4'h6) ? BIU_REGISTER_REG :
|
||||
(eu_opcode_op1_sel==4'h7) ? BIU_RETURN_DATA :
|
||||
(eu_opcode_op1_sel==4'h8) ? PFQ_ADDR_OUT :
|
||||
(eu_opcode_op1_sel==4'h9) ? eu_register_r0 :
|
||||
(eu_opcode_op1_sel==4'hA) ? eu_register_r1 :
|
||||
(eu_opcode_op1_sel==4'hB) ? eu_register_r2 :
|
||||
(eu_opcode_op1_sel==4'hC) ? eu_register_r3 :
|
||||
(eu_opcode_op1_sel==4'hD) ? eu_alu_last_result :
|
||||
(eu_opcode_op1_sel==4'hE) ? system_signals :
|
||||
eu_opcode_immediate ;
|
||||
|
||||
|
||||
|
||||
// JUMP condition codes
|
||||
assign eu_jump_boolean = (eu_opcode_jump_cond==4'h0) ? 1'b1 : // unconditional jump
|
||||
(eu_opcode_jump_cond==4'h1 && eu_alu_last_result!=16'h0) ? 1'b1 :
|
||||
(eu_opcode_jump_cond==4'h2 && eu_alu_last_result==16'h0) ? 1'b1 :
|
||||
1'b0 ;
|
||||
|
||||
|
||||
|
||||
// Consolidated system signals
|
||||
assign system_signals[13] = eu_add_carry8;
|
||||
assign system_signals[12] = BIU_CLK_COUNTER_ZERO;
|
||||
assign system_signals[11] = eu_add_overflow16;
|
||||
assign system_signals[9] = eu_add_overflow8;
|
||||
assign system_signals[8] = eu_tr_latched;
|
||||
assign system_signals[7] = ~PFQ_EMPTY;
|
||||
assign system_signals[6] = biu_done_caught;
|
||||
assign system_signals[5] = TEST_N_INT;
|
||||
assign system_signals[4] = eu_add_aux_carry;
|
||||
assign system_signals[3] = BIU_NMI_CAUGHT;
|
||||
assign system_signals[2] = eu_parity;
|
||||
assign system_signals[1] = intr_asserted;
|
||||
assign system_signals[0] = eu_add_carry;
|
||||
|
||||
|
||||
assign eu_prefix_repnz = eu_flags[15];
|
||||
assign eu_prefix_rep = eu_flags[14];
|
||||
assign eu_prefix_lock = eu_flags[13];
|
||||
assign BIU_NMI_DEBOUNCE = eu_flags[12];
|
||||
assign eu_flag_o = eu_flags[11];
|
||||
assign eu_flag_d = eu_flags[10];
|
||||
assign eu_flag_i = eu_flags[9];
|
||||
assign eu_flag_t = eu_flags[8];
|
||||
assign eu_flag_s = eu_flags[7];
|
||||
assign eu_flag_z = eu_flags[6];
|
||||
assign eu_tf_debounce = eu_flags[5];
|
||||
assign eu_flag_a = eu_flags[4];
|
||||
assign eu_nmi_pending = eu_flags[3];
|
||||
assign eu_flag_p = eu_flags[2];
|
||||
assign eu_flag_temp = eu_flags[1];
|
||||
assign eu_flag_c = eu_flags[0];
|
||||
|
||||
|
||||
|
||||
// EU ALU Operations
|
||||
// ------------------------------------------
|
||||
// eu_alu0 = NOP
|
||||
// eu_alu1 = JUMP
|
||||
assign eu_alu2 = adder_out; // ADD
|
||||
assign eu_alu3 = { eu_operand0[7:0] , eu_operand0[15:8] }; // BYTESWAP
|
||||
assign eu_alu4 = eu_operand0 & eu_operand1; // AND
|
||||
assign eu_alu5 = eu_operand0 | eu_operand1; // OR
|
||||
assign eu_alu6 = eu_operand0 ^ eu_operand1; // XOR
|
||||
assign eu_alu7 = { 1'b0 , eu_operand0[15:1] }; // SHR
|
||||
|
||||
|
||||
|
||||
|
||||
// Mux the ALU operations
|
||||
assign eu_alu_out = (eu_opcode_type==3'h2) ? eu_alu2 :
|
||||
(eu_opcode_type==3'h3) ? eu_alu3 :
|
||||
(eu_opcode_type==3'h4) ? eu_alu4 :
|
||||
(eu_opcode_type==3'h5) ? eu_alu5 :
|
||||
(eu_opcode_type==3'h6) ? eu_alu6 :
|
||||
(eu_opcode_type==3'h7) ? eu_alu7 :
|
||||
20'hEEEEE;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Generate 16-bit full adder for the EU
|
||||
assign carry[0] = 1'b0;
|
||||
genvar i;
|
||||
generate
|
||||
for (i=0; i < 16; i=i+1)
|
||||
begin : GEN_ADDER
|
||||
assign adder_out[i] = eu_operand0[i] ^ eu_operand1[i] ^ carry[i];
|
||||
assign carry[i+1] = (eu_operand0[i] & eu_operand1[i]) | (eu_operand0[i] & carry[i]) | (eu_operand1[i] & carry[i]);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign eu_parity = ~(eu_alu_last_result[0]^eu_alu_last_result[1]^eu_alu_last_result[2]^eu_alu_last_result[3]^eu_alu_last_result[4]^eu_alu_last_result[5]^eu_alu_last_result[6]^eu_alu_last_result[7]);
|
||||
|
||||
|
||||
assign eu_biu_req = eu_biu_command[9];
|
||||
|
||||
assign intr_asserted = BIU_INTR & intr_enable_delayed;
|
||||
|
||||
|
||||
assign new_instruction = (eu_rom_address[12:8]==5'h01) ? 1'b1 : 1'b0;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
//
|
||||
// EU Microsequencer
|
||||
//
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
always @(posedge CORE_CLK_INT)
|
||||
begin : EU_MICROSEQUENCER
|
||||
|
||||
if (RESET_INT==1'b1)
|
||||
begin
|
||||
biu_done_d1 <= 'h0;
|
||||
biu_done_d2 <= 'h0;
|
||||
eu_biu_req_d1 <= 'h0;
|
||||
biu_done_caught <= 'h0;
|
||||
eu_flag_t_d <= 'h0;
|
||||
eu_tr_latched <= 'h0;
|
||||
eu_add_carry <= 'h0;
|
||||
eu_add_carry8 <= 'h0;
|
||||
eu_add_aux_carry <= 'h0;
|
||||
eu_add_overflow16 <= 'h0;
|
||||
eu_add_overflow8 <= 'h0;
|
||||
eu_alu_last_result <= 'h0;
|
||||
eu_register_ax <= 'h0;
|
||||
eu_register_bx <= 'h0;
|
||||
eu_register_cx <= 'h0;
|
||||
eu_register_dx <= 'h0;
|
||||
eu_register_sp <= 'h0;
|
||||
eu_register_bp <= 'h0;
|
||||
eu_register_si <= 'h0;
|
||||
eu_register_di <= 'h0;
|
||||
eu_flags <= 'h0;
|
||||
eu_register_r0 <= 'h0;
|
||||
eu_register_r1 <= 'h0;
|
||||
eu_register_r2 <= 'h0;
|
||||
eu_register_r3 <= 'h0;
|
||||
eu_biu_command <= 'h0;
|
||||
eu_biu_dataout <= 'h0;
|
||||
eu_stall_pipeline <= 'h0;
|
||||
eu_rom_address <= 13'h0020;
|
||||
eu_calling_address <= 'h0;
|
||||
intr_enable_delayed <= 1'b0;
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
|
||||
// Delay the INTR enable flag until after the next instruction begins.
|
||||
// No delay when it is disabled.
|
||||
if (eu_flag_i==1'b0)
|
||||
begin
|
||||
intr_enable_delayed <= 1'b0;
|
||||
end
|
||||
else
|
||||
if (new_instruction==1'b1)
|
||||
begin
|
||||
intr_enable_delayed <= eu_flag_i;
|
||||
end
|
||||
|
||||
// Latch the TF flag on its rising edge.
|
||||
eu_flag_t_d <= eu_flag_t;
|
||||
if (eu_flag_t_d==1'b0 && eu_flag_t==1'b1)
|
||||
begin
|
||||
eu_tr_latched <= 1'b1;
|
||||
end
|
||||
else if (eu_tf_debounce==1'b1)
|
||||
begin
|
||||
eu_tr_latched <= 1'b0;
|
||||
end
|
||||
|
||||
|
||||
|
||||
// Latch the done bit from the biu.
|
||||
// Debounce it when the request is released.
|
||||
biu_done_d1 <= BIU_DONE;
|
||||
biu_done_d2 <= biu_done_d1;
|
||||
eu_biu_req_d1 <= eu_biu_req;
|
||||
if (biu_done_d2==1'b0 && biu_done_d1==1'b1)
|
||||
biu_done_caught <= 1'b1;
|
||||
else if (eu_biu_req_d1==1'b1 && eu_biu_req==1'b0)
|
||||
biu_done_caught <= 1'b0;
|
||||
|
||||
|
||||
|
||||
// Generate and store flags for addition
|
||||
if (eu_stall_pipeline==1'b0 && eu_opcode_type==3'h2)
|
||||
begin
|
||||
eu_add_carry <= carry[16];
|
||||
eu_add_carry8 <= carry[8];
|
||||
eu_add_aux_carry <= carry[4];
|
||||
eu_add_overflow16 <= carry[16] ^ carry[15];
|
||||
eu_add_overflow8 <= carry[8] ^ carry[7];
|
||||
end
|
||||
|
||||
|
||||
// Register writeback
|
||||
if (eu_stall_pipeline==1'b0 && eu_opcode_type!=3'h0 && eu_opcode_type!=3'h1)
|
||||
begin
|
||||
eu_alu_last_result <= eu_alu_out[15:0];
|
||||
case (eu_opcode_dst_sel) // synthesis parallel_case
|
||||
4'h0 : eu_register_ax <= eu_alu_out[15:0];
|
||||
4'h1 : eu_register_bx <= eu_alu_out[15:0];
|
||||
4'h2 : eu_register_cx <= eu_alu_out[15:0];
|
||||
4'h3 : eu_register_dx <= eu_alu_out[15:0];
|
||||
4'h4 : eu_register_sp <= eu_alu_out[15:0];
|
||||
4'h5 : eu_register_bp <= eu_alu_out[15:0];
|
||||
4'h6 : eu_register_si <= eu_alu_out[15:0];
|
||||
4'h7 : eu_register_di <= eu_alu_out[15:0];
|
||||
4'h8 : eu_flags <= eu_alu_out[15:0];
|
||||
4'h9 : eu_register_r0 <= eu_alu_out[15:0];
|
||||
4'hA : eu_register_r1 <= eu_alu_out[15:0];
|
||||
4'hB : eu_register_r2 <= eu_alu_out[15:0];
|
||||
4'hC : eu_register_r3 <= eu_alu_out[15:0];
|
||||
4'hD : eu_biu_command <= eu_alu_out[15:0];
|
||||
//4'hE : ;
|
||||
4'hF : eu_biu_dataout <= eu_alu_out[15:0];
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
// JUMP Opcode
|
||||
if (eu_stall_pipeline==1'b0 && eu_opcode_type==3'h1 && eu_jump_boolean==1'b1)
|
||||
begin
|
||||
eu_stall_pipeline <= 1'b1;
|
||||
|
||||
// For subroutine CALLs, store next opcode address
|
||||
if (eu_opcode_jump_call==1'b1)
|
||||
begin
|
||||
eu_calling_address[51:0] <= {eu_calling_address[38:0] , eu_rom_address[12:0] }; // 4 deep calling addresses
|
||||
end
|
||||
|
||||
case (eu_opcode_jump_src) // synthesis parallel_case
|
||||
3'h0 : eu_rom_address <= eu_opcode_immediate[12:0];
|
||||
3'h1 : eu_rom_address <= { 4'b0 , 1'b1 , PFQ_TOP_BYTE }; // If only used for primary opcode jump, maybe make fixed prepend rather than immediate value prepend?
|
||||
3'h2 : eu_rom_address <= { eu_opcode_immediate[4:0], PFQ_TOP_BYTE[7:6] , PFQ_TOP_BYTE[2:0] , 3'b000 }; // Rearranged mod_reg_rm byte - imm,MOD,RM,000
|
||||
3'h3 : begin
|
||||
eu_rom_address <= eu_calling_address[12:0];
|
||||
eu_calling_address[38:0] <= eu_calling_address[51:13];
|
||||
end
|
||||
3'h4 : eu_rom_address <= { eu_opcode_immediate[7:0], eu_biu_dataout[3:0] , 1'b0 }; // Jump table for EA register fetch decoding. Jump Addresses decoded from biu_dataout.
|
||||
3'h5 : eu_rom_address <= { eu_opcode_immediate[6:0], eu_biu_dataout[3:0] , 2'b00 }; // Jump table for EA register writeback decoding. Jump Addresses decoded from biu_dataout.
|
||||
3'h6 : eu_rom_address <= { eu_opcode_immediate[12:3], eu_biu_dataout[5:3] }; // Jump table for instructions that share same opcode and decode using the REG field.
|
||||
|
||||
default : ;
|
||||
endcase
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
eu_stall_pipeline <= 1'b0; // Debounce the pipeline stall
|
||||
eu_rom_address <= eu_rom_address + 1'b1;
|
||||
end
|
||||
|
||||
end
|
||||
end // EU Microsequencer
|
||||
|
||||
|
||||
|
||||
|
||||
endmodule // eu.v
|
||||
3962
common/CPU/8088/microcode.mem
Normal file
3962
common/CPU/8088/microcode.mem
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user