Line 59... |
Line 59... |
// interrupt enable register
|
// interrupt enable register
|
input [3:0] intr_ena; // set high to enable respective interrupt
|
input [3:0] intr_ena; // set high to enable respective interrupt
|
|
|
//---------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------
|
// 8080 assembly code constants
|
// 8080 assembly code constants
|
// call instruction opcode used to call interrupt routine
|
// RST instruction opcode used to call interrupt routines at addresses
|
`define CALL_INST 8'hcd
|
// int0: 0x08 / int1: 0x18 / int2: 0x28 / int3: 0x38
|
// interrupt vectors fixed addresses - high address byte is 0
|
`define RST_1_INST 8'hcf
|
`define INT0_VEC 8'h08
|
`define RST_3_INST 8'hdf
|
`define INT1_VEC 8'h18
|
`define RST_5_INST 8'hef
|
`define INT2_VEC 8'h28
|
`define RST_7_INST 8'hff
|
`define INT3_VEC 8'h38
|
|
|
|
//---------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------
|
// internal declarations
|
// internal declarations
|
// registered output
|
// registered output
|
reg [7:0] cpu_inst;
|
reg [7:0] cpu_inst;
|
Line 103... |
Line 102... |
else if (act_int[3]) intSel <= 2'd2;
|
else if (act_int[3]) intSel <= 2'd2;
|
else intSel <= 2'd3;
|
else intSel <= 2'd3;
|
// switch to next state
|
// switch to next state
|
intSq <= 2'd1;
|
intSq <= 2'd1;
|
end
|
end
|
default: // all other states increment the state register on inta read
|
2'd1: // wait for inta read cycle
|
if (cpu_inta && cpu_rd)
|
if (cpu_inta && cpu_rd)
|
begin
|
begin
|
// update state
|
// update instruction opcode
|
intSq <= intSq + 1;
|
cpu_inst <= int_vec;
|
|
// switch to end for inta release
|
// update instruction opcode for each byte read during inta
|
intSq <= 2'd2;
|
case (intSq)
|
|
2'd1: cpu_inst <= `CALL_INST;
|
|
2'd2: cpu_inst <= int_vec;
|
|
default: cpu_inst <= 8'd0;
|
|
endcase
|
|
end
|
end
|
else if (!cpu_inta)
|
default: // wait for inta end
|
|
if (!cpu_inta)
|
begin
|
begin
|
intSq <= 2'd0;
|
// reset state machine
|
cpu_inst <= 8'd0;
|
intSq <= 2'b0;
|
|
cpu_inst <= 8'b0;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
|
|
// assign interrupt vector address according to selected interrupt
|
// assign interrupt vector address according to selected interrupt
|
always @ (intSel)
|
always @ (intSel)
|
begin
|
begin
|
case (intSel)
|
case (intSel)
|
2'd0: int_vec <= `INT0_VEC;
|
2'd0: int_vec <= `RST_1_INST;
|
2'd1: int_vec <= `INT1_VEC;
|
2'd1: int_vec <= `RST_3_INST;
|
2'd2: int_vec <= `INT2_VEC;
|
2'd2: int_vec <= `RST_5_INST;
|
2'd3: int_vec <= `INT3_VEC;
|
2'd3: int_vec <= `RST_7_INST;
|
endcase
|
endcase
|
end
|
end
|
|
|
// latch active interrupt on rising edge
|
// latch active interrupt on rising edge
|
always @ (posedge reset or posedge clock)
|
always @ (posedge reset or posedge clock)
|
Line 150... |
Line 146... |
assign cpu_intr = |act_int;
|
assign cpu_intr = |act_int;
|
|
|
// clear serviced interrupt
|
// clear serviced interrupt
|
always @ (cpu_inta or cpu_rd or intSq or intSel)
|
always @ (cpu_inta or cpu_rd or intSq or intSel)
|
begin
|
begin
|
if (cpu_inta && cpu_rd && (intSq == 2'd3))
|
if (cpu_inta && cpu_rd && (intSq == 2'd1))
|
begin
|
begin
|
case (intSel)
|
case (intSel)
|
2'd0: int_clr <= 4'b0001;
|
2'd0: int_clr <= 4'b0001;
|
2'd1: int_clr <= 4'b0010;
|
2'd1: int_clr <= 4'b0010;
|
2'd2: int_clr <= 4'b0100;
|
2'd2: int_clr <= 4'b0100;
|