📄 a86_idecoder.v
字号:
// http://gforge.openchip.org/projects/a86
//
//
//
`include "timescale.v"
`include "a86_defines.v"
module a86_idecoder(
clk,empty,
i0,i1,i2,i3,i4,i5,
opcode,addrmode,
data16,data16_hi,
icode
);
input clk;
output empty;
input [7:0] i0;
input [7:0] i1;
input [7:0] i2;
input [7:0] i3;
input [7:0] i4;
input [7:0] i5;
output [7:0] opcode;
output [7:0] addrmode;
output [15:0] data16;
output [15:0] data16_hi;
output [`a86_icode_width-1:0] icode;
reg [`a86_icode_width-1:0] icode;
reg [7:0] opcode;
reg [7:0] addrmode;
reg [15:0] data16;
reg [15:0] data16_hi;
// route/mux opcode bytes
// opcode is 1st
always @ (i1) opcode = i1;
// addrmode is 2nd
always @ (i2) addrmode = i2;
// if 16:16 data is present hi word is {4,5} always
always @ (i4,i5) data16_hi = {i5, i4};
// if 16 bit data is present it is 2,3 or 3,4 mux it here!
always @ (i1,i2,i3,i4)
case (i1[1])
1'b0: data16 = {i2,i3};
default data16 = {i3,i4};
endcase
// duplicate instruction over icode bus in case some module needs it directly!
always @ (i1,i2,i3,i4,i5) begin
icode[`a86_icode_i_start+7:`a86_icode_i_start] = i1;
icode[`a86_icode_i_start+15:`a86_icode_i_start+8] = i2;
icode[`a86_icode_i_start+23:`a86_icode_i_start+16] = i3;
icode[`a86_icode_i_start+31:`a86_icode_i_start+24] = i4;
icode[`a86_icode_i_start+39:`a86_icode_i_start+32] = i5;
end
// (Micro) Instruction Decoder
// Magic is required here!
reg i0valid;
always @ (i0) i0valid = 1; // dummmy goaway
reg i1valid;
always @ (i1) i1valid = 1; // dummmy goaway
// single bit to hold LOCK prefix i(-1)
reg lock;
reg x40;
reg x70;
reg B0;
reg E0;
reg F0;
always @ (i1)
if (i1[7:4] == 4'b0100) x40 = #1 1;
else x40 = #1 0;
always @ (i1)
if (i1[7:4] == 4'b1011) B0 = #1 1;
else B0 = #1 0;
always @ (i1)
if (i1[7:4] == 4'b1110) E0 = #1 1;
else E0 = #1 0;
always @ (i1)
if (i1[7:4] == 4'b1111) F0 = #1 1;
else F0 = #1 0;
// Decode Prefix if i0 is valid (i.e. Prefix present)
// if LOCK prefix, we should only store on bit "LOCK" and empty i0
//
always @ (i0,i0valid) begin
// Segment override ?
// CS 0010 1110
// DS 0011 1110
// ES 0010 0110
// SS 0011 0110
// xx 001X X110
case ( {i0[7:5],i0[2:0]} )
6'b001110: icode[`icode_seg_override] = i0valid;
default icode[`icode_seg_override] = 0;
endcase
// REP
// .. 1111 0010
// .. 1111 0011
// xx 1111 001X
case ( i0[7:1] )
7'b1111001: icode[`icode_rep_prefix] = i0valid;
default icode[`icode_rep_prefix] = 0;
endcase
end
// Lock Prefix?
always @ (posedge clk)
if (i0 == 8'b11110000) lock <= i0valid;
else lock <= 0;
// rout it out
always @ (lock)
icode[`icode_lock_prefix] = lock;
// Decode Instruction (done here partially?)
// 0111 xxxx Jcc
// 1110 00xx LOOP, JCXZ
// 1110 10xx JMP
// 1110 1011 JMP disp8
// 1110 1001 JMP disp16
// 1110 1010 JMP ptr16:16
// 1110 1000 CALL disp16
reg i_jr;
// Relative jumps and LOOP things
always @ (i1, E0) begin
if ( (i1[7:4]==4'b0111) // Jcc
| (E0 & (i1[3:2]==2'b00)) // LOOP, JCXZ
| (E0 & (i1[3:0]==4'b1011)) // JMP rel8
) i_jr = 1;
else i_jr = 0;
end
always @ (i1,i_jr,i1valid) begin
icode[`a86_icode_jr] = i_jr;
// ADSU
// ADC 0001 00xx
// ADC 1000 00xx xx01 0xxx
// ADD 0000 00xx
// ADD 1000 00xx xx00 0xxx
// SBB 0001 10xx
// SBB 1000 00xx xx01 1xxx
// SUB 0010 10xx
// SUB 1000 00xx xx10 1xxx
// INC 0100 0xxx
// INC 1111 111x xx00 0xxx
// DEC 0100 1xxx
// DEC 1111 111x xx00 10xxx
end
always @ (E0,i1,i_jr) begin
if (E0 & (i1[3:2]==2'b00) & (i1[1:0] != 2'b11)) icode[`a86_icode_dec_cx] = 1;
else icode[`a86_icode_dec_cx] = 0;
end
// INC DEC reg
always @ (x40)
if ( x40 == 1) icode[`a86_icode_incdec] = 1;
else icode[`a86_icode_incdec] = 0;
// direct write to PC
// EA
always @ (i1) begin
// Load PC from immediate word!
if ((i1[7:1] == 7'b1110101) ) icode[`a86_icode_ip_wr] = #1 1;
else icode[`a86_icode_ip_wr] = #1 0;
end
// In or Out
//
// 1110 010w in im
// 1110 110w in r
// 1110 011w out im
// 1110 111w out r
always @ (i1, E0)
if ( E0 & i1[2] ) icode[`a86_icode_inout] = #1 1;
else icode[`a86_icode_inout] = #1 0;
always @ (i1, E0)
if ( E0 & i1[2] & (i1[1]==0) ) icode[`a86_icode_in] = #1 1;
else icode[`a86_icode_in] = #1 0;
always @ (i1, E0)
if ( E0 & i1[2] & i1[1] ) icode[`a86_icode_out] = #1 1;
else icode[`a86_icode_out] = #1 0;
reg i_aaa;
reg i_aad;
reg i_aam;
reg i_aas;
reg i_cbw;
reg i_cwd;
reg i_daa;
reg i_das;
reg i_1_byte;
reg i_2_byte;
reg i_3_byte;
reg i_4_byte;
reg i_5_byte;
reg alub_immed;
reg alub_immed_3b;
always @(i1)
if (i1[7:2] == 6'b100000) alub_immed = 1;
else alub_immed = 0;
always @(alub_immed)
icode[`a86_icode_alub_immed] = alub_immed;
always @(i1,B0)
if (B0 | ((i1[7:6] == 2'b00) & (i1[2:1] == 2'b10)) ) alub_immed_3b = 1;
else alub_immed_3b = 0;
always @(alub_immed_3b)
icode[`a86_icode_alub_immed_3b] = alub_immed_3b;
// one byte instruction ?
always @ (i_aaa,i_aas,i_cbw,i_cwd,i_daa,i_das,i1,icode)
i_1_byte = i_aaa | i_aas | i_cbw | i_cwd | i_daa | i_das
| (icode[`a86_icode_inout] & i1[3])
;
always @(i_1_byte) #0 icode[`a86_icode_1_byte_instr] = i_1_byte;
always @(i_daa,i_das,i1,icode) begin
i_2_byte = icode[`a86_icode_jr]
| ( i1[7:2] == 6'b111001 );
end
always @(i_2_byte) #0 icode[`a86_icode_2_byte_instr] = i_2_byte;
always @(alub_immed_3b) begin
i_3_byte = alub_immed_3b;
end
always @(i_3_byte) #0 icode[`a86_icode_3_byte_instr] = i_3_byte;
always @(alub_immed) begin
i_4_byte = alub_immed;
end
always @(i_4_byte) #0 icode[`a86_icode_4_byte_instr] = i_4_byte;
// Calc Instruction size!
reg [2:0] i_size;
always @(i_1_byte,i_2_byte,i_3_byte,i_4_byte) begin
if (i_2_byte) i_size = #1 3'b010;
else if (i_3_byte) i_size = #1 3'b011;
else if (i_4_byte) i_size = #1 3'b100;
else if (i_5_byte) i_size = #1 3'b101;
else i_size = #1 3'b001;
end
always @(i_size)
icode[`a86_icode_instr_size+2:`a86_icode_instr_size] = i_size[2:0];
// Write to REGs (AX, BX, CX, DX)
/*
*/
reg wr_AX_BX_CX_BX;
always @(icode) begin
// IN instruction!
// INC DEC register ?
// wr_AX_BX_CX_BX = icode[`a86_icode_in] | icode[`a86_icode_incdec];
icode[`a86_icode_iobus_we] = icode[`a86_icode_out] ;
// for OUT commands pass register to IO
icode[`a86_icode_alu_sela] = icode[`a86_icode_out];
// for IN commands pass IO to register
// also for MOV reg, immed!
icode[`a86_icode_alu_selb] = icode[`a86_icode_in] | B0;
end
//always @(wr_AX_BX_CX_BX) icode[`a86_icode_wr_ax_bx_cx_dx] = wr_AX_BX_CX_BX;
reg [2:0] reg_sel2_i1_bits; // select bits in i1
reg [2:0] reg_sel2_aux_bits; // select bits in aux field
reg [2:0] reg_sel2_rm_bits; // select bits in rm field
reg [2:0] reg_sel2_bits;
reg aux_in_use; // aux field is in use
// reg selector is in i1 (2:0) INC, DEC
always @(x40,B0, i1)
if (x40 | B0) reg_sel2_i1_bits = i1[2:0];
else reg_sel2_i1_bits = 3'b000;
// aux field?
always @(aux_in_use,i2)
if (aux_in_use) reg_sel2_aux_bits = 3'b000;
else reg_sel2_aux_bits = 3'b000;
// immed 4 byte
always @(alub_immed,i2)
if (alub_immed) reg_sel2_rm_bits = i2[2:0];
else reg_sel2_rm_bits = 3'b000;
always @(reg_sel2_i1_bits, reg_sel2_aux_bits,reg_sel2_rm_bits)
reg_sel2_bits = reg_sel2_i1_bits | reg_sel2_aux_bits | reg_sel2_rm_bits;
// sec operand select register
reg sel2_AX;
reg sel2_BX;
reg sel2_CX;
reg sel2_DX;
// sec operand write register
reg wr2_AX;
reg wr2_BX;
reg wr2_CX;
reg wr2_DX;
reg wr2reg;
always @(x40,alub_immed,alub_immed_3b)
wr2reg = x40 | alub_immed | alub_immed_3b;
always @(reg_sel2_bits)
if (reg_sel2_bits == 3'b000) sel2_AX = 1;
else sel2_AX = 0;
always @(reg_sel2_bits)
if (reg_sel2_bits == 3'b011) sel2_BX = 1;
else sel2_BX = 0;
always @(reg_sel2_bits)
if (reg_sel2_bits == 3'b001) sel2_CX = 1;
else sel2_CX = 0;
always @(reg_sel2_bits)
if (reg_sel2_bits == 3'b010) sel2_DX = 1;
else sel2_DX = 0;
always @(wr2reg,sel2_AX)
if (wr2reg == 1) wr2_AX = sel2_AX;
else wr2_AX = 0;
always @(wr2reg,sel2_BX)
if (wr2reg == 1) wr2_BX = sel2_BX;
else wr2_BX = 0;
always @(wr2reg,sel2_CX,icode)
if (wr2reg == 1) wr2_CX = sel2_CX;
else wr2_CX = icode[`a86_icode_dec_cx];
always @(wr2reg,sel2_DX)
if (wr2reg == 1) wr2_DX = sel2_DX;
else wr2_DX = 0;
always @(sel2_AX,icode)
icode[`a86_icode_sel_ax] = sel2_AX | icode[`a86_icode_out];
always @(sel2_BX)
icode[`a86_icode_sel_bx] = sel2_BX;
always @(sel2_CX)
icode[`a86_icode_sel_cx] = sel2_CX;
always @(sel2_DX)
icode[`a86_icode_sel_dx] = sel2_DX;
always @(wr2_AX,icode)
icode[`a86_icode_wr_ax] = wr2_AX | icode[`a86_icode_in];
always @(wr2_BX)
icode[`a86_icode_wr_bx] = wr2_BX;
always @(wr2_CX)
icode[`a86_icode_wr_cx] = wr2_CX;
always @(wr2_DX)
icode[`a86_icode_wr_dx] = wr2_DX;
// Select ALU Op
reg [2:0] alu_sel_immed;
reg [2:0] alu_sel_norm;
reg [2:0] alu_sel;
always @(alub_immed,i1,i2)
if (alub_immed) alu_sel_immed = i2[5:3]; // ALU op is in aux!
else alu_sel_immed = 3'b000;
always @(i1,i2)
if ( i1[7:6] == 2'b00) alu_sel_norm = i1[5:3]; // ALU op is in aux!
else alu_sel_norm = 3'b000;
always @(alu_sel_immed,alu_sel_norm)
alu_sel = alu_sel_immed | alu_sel_norm;
// select lines for ALU
always @(alu_sel)
if (alu_sel == 3'b100) icode[`a86_icode_alu_and] = 1;
else icode[`a86_icode_alu_and] = 0;
always @(alu_sel)
if (alu_sel == 3'b001) icode[`a86_icode_alu_or] = 1;
else icode[`a86_icode_alu_or] = 0;
always @(alu_sel)
if (alu_sel == 3'b110) icode[`a86_icode_alu_xor] = 1;
else icode[`a86_icode_alu_xor] = 0;
// immed operand as second?
/*
ALU OP
1000 00sw mm AAA rrr data16 (4 byte)
00AA A0dw mm reg r/m
00AA A10w ax,data16 (3 byte)
010 ADC
000 ADD
111 CMP
101 SUB
011 SBB
100 AND
001 OR
110 XOR
*/
/*
`define a86_icode_alu_adsu 33 //
`define a86_icode_alu_adsu_add 34 //
`define a86_icode_incdec 35 //
`define a86_icode_alu_and 37 //
`define a86_icode_alu_or 38 //
`define a86_icode_alu_xor 39 //
`define a86_icode_alu_sela 40 //
`define a86_icode_alu_selb 41 //
*/
endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -