Line 49... |
Line 49... |
// In order to couple the CPU unit with a single bus, these sepparate data/instruction buses must be multiplexed by
|
// In order to couple the CPU unit with a single bus, these sepparate data/instruction buses must be multiplexed by
|
// a dedicated bus interface unit (BIU).
|
// a dedicated bus interface unit (BIU).
|
// It is able to execute up to 40Mips on Spartan XC3S700AN speed grade -4, performances comparable with a 486 CPU.
|
// It is able to execute up to 40Mips on Spartan XC3S700AN speed grade -4, performances comparable with a 486 CPU.
|
// Small size, the CPU + BIU requires ~25% or 1500 slices - on Spartan XC3S700AN
|
// Small size, the CPU + BIU requires ~25% or 1500 slices - on Spartan XC3S700AN
|
//
|
//
|
|
// 16May2012 - fixed CMPS/SCAS bug when interrupted on the <equal> item
|
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
`timescale 1ns / 1ps
|
`timescale 1ns / 1ps
|
|
|
module Next186_CPU(
|
module Next186_CPU(
|
output [19:0] ADDR,
|
output [19:0] ADDR,
|
Line 176... |
Line 177... |
// interrupts
|
// interrupts
|
wire SAMPLEINT = ~(WE[2] & RASEL[1:0] == 2'b10) & ~status[2] & ~status[4] & ~status[5]; // not load SS, no prefix
|
wire SAMPLEINT = ~(WE[2] & RASEL[1:0] == 2'b10) & ~status[2] & ~status[4] & ~status[5]; // not load SS, no prefix
|
wire NMIACK = SNMI & ~FNMI; // NMI acknowledged
|
wire NMIACK = SNMI & ~FNMI; // NMI acknowledged
|
wire INTRACK = FLAGS[9] & (~WE[4] | FIN[9]) & SINTR; // INTR acknowledged (IF and not CLI in progress)
|
wire INTRACK = FLAGS[9] & (~WE[4] | FIN[9]) & SINTR; // INTR acknowledged (IF and not CLI in progress)
|
wire IACK = IRQ | (SAMPLEINT & (NMIACK | INTRACK)) | (~WE[2] & ~HALT & FLAGS[8]); // interrupt acknowledged
|
wire IACK = IRQ | (SAMPLEINT & (NMIACK | INTRACK)) | (~WE[2] & ~HALT & FLAGS[8]); // interrupt acknowledged
|
|
reg CMPS; // early EQ test for CMPS
|
|
reg SCAS; // early EQ test for SCAS
|
|
|
Next186_Regs REGS (
|
Next186_Regs REGS (
|
.RASEL(RASEL),
|
.RASEL(RASEL),
|
.RBSEL(RBSEL),
|
.RBSEL(RBSEL),
|
.BASEL(BASEL),
|
.BASEL(BASEL),
|
Line 288... |
Line 291... |
FETCH[2] <= INSTR[23:16];
|
FETCH[2] <= INSTR[23:16];
|
FETCH[1] <= INSTR[15:8];
|
FETCH[1] <= INSTR[15:8];
|
FETCH[0] <= INSTR[7:0];
|
FETCH[0] <= INSTR[7:0];
|
STAGE <= 0;
|
STAGE <= 0;
|
CPUStatus[5:0] <= status[5:0];
|
CPUStatus[5:0] <= status[5:0];
|
TZF <= status[3];
|
|
ICODE1 <= ICODE(INSTR[7:0]);
|
ICODE1 <= ICODE(INSTR[7:0]);
|
end else begin // no interrupt, no fetch
|
end else begin // no interrupt, no fetch
|
STAGE <= STAGE + {DIVSTAGE, ALUSTAGE} + 1;
|
STAGE <= STAGE + {DIVSTAGE, ALUSTAGE} + 1;
|
if(&DOSEL) {FETCH[3], FETCH[2]} <= |DISEL ? DIN : RB;
|
if(&DOSEL) {FETCH[3], FETCH[2]} <= |DISEL ? DIN : RB;
|
TZF <= FIN[6]; // zero flag for REP
|
TZF <= FIN[6]; // zero flag for BOUND
|
TLF <= FIN[7] != FIN[11]; // less flag for BOUND
|
TLF <= FIN[7] != FIN[11]; // less flag for BOUND
|
end
|
end
|
end
|
end
|
if(IFETCH & ~status[2] & ~status[4] & ~status[5]) CRTIP <= IPIN; // no prefix
|
if(IFETCH & ~status[2] & ~status[4] & ~status[5]) CRTIP <= IPIN; // no prefix
|
SRST <= RST; // level detection RST
|
SRST <= RST; // level detection RST
|
Line 307... |
Line 309... |
SNMI <= 1'b0;
|
SNMI <= 1'b0;
|
FNMI <= 1'b0;
|
FNMI <= 1'b0;
|
end
|
end
|
if(~|STAGE[1:0]) DIVQSGN <= QSGN;
|
if(~|STAGE[1:0]) DIVQSGN <= QSGN;
|
RDIVEXC <= DIVOP & DIVEXC & ~IDIV; // bit 8/16 for unsigned DIV
|
RDIVEXC <= DIVOP & DIVEXC & ~IDIV; // bit 8/16 for unsigned DIV
|
|
CMPS <= (~FETCH[0][0] | (FETCH[3] == DIN[15:8])) & (FETCH[2] == DIN[7:0]); // early EQ test for CMPS
|
|
SCAS <= (~FETCH[0][0] | (AX[15:8] == DIN[15:8])) & (AX[7:0] == DIN[7:0]); // early EQ test for SCAS
|
end
|
end
|
|
|
always @(ISEL, FETCH[0], FETCH[1], FETCH[2], FETCH[3], FETCH[4], FETCH[5])
|
always @(ISEL, FETCH[0], FETCH[1], FETCH[2], FETCH[3], FETCH[4], FETCH[5])
|
case(ISEL)
|
case(ISEL)
|
2'b00: DIMM1 = {FETCH[2], FETCH[1]};
|
2'b00: DIMM1 = {FETCH[2], FETCH[1]};
|
Line 332... |
Line 336... |
3'b110: ISIZEI = 6;
|
3'b110: ISIZEI = 6;
|
default: ISIZEI = 5;
|
default: ISIZEI = 5;
|
endcase
|
endcase
|
end
|
end
|
|
|
always @(FETCH[0], FETCH[1], FETCH[2], FETCH[3], FETCH[4], FETCH[5], MOD, REG, RM, CPUStatus, USEBP, NOBP, RASEL, ISIZEI, TLF, EAC, COUT, DIVEND, DIVC, QSGN,
|
always @(FETCH[0], FETCH[1], FETCH[2], FETCH[3], FETCH[4], FETCH[5], MOD, REG, RM, CPUStatus, USEBP, NOBP, RASEL, ISIZEI, TLF, EAC, COUT, DIVEND, DIVC, QSGN, CMPS, SCAS,
|
WBIT, ISIZES, ISELS, WRBIT, ISIZEW, STAGE, NULLSHIFT, ALUCONT, FLAGS, CXZ, RCXZ, NRORCXLE1, TZF, JMPC, LOOPC, ICODE1, DIVQSGN, DIVSGN, DIVRSGN, SOUT) begin
|
WBIT, ISIZES, ISELS, WRBIT, ISIZEW, STAGE, NULLSHIFT, ALUCONT, FLAGS, CXZ, RCXZ, NRORCXLE1, TZF, JMPC, LOOPC, ICODE1, DIVQSGN, DIVSGN, DIVRSGN, SOUT) begin
|
WORD = FETCH[0][0];
|
WORD = FETCH[0][0];
|
BASEL = FETCH[0][1] | &MOD;
|
BASEL = FETCH[0][1] | &MOD;
|
RASEL = FETCH[0][1] ? REG : RM; // destination
|
RASEL = FETCH[0][1] ? REG : RM; // destination
|
BBSEL = {1'b0, !FETCH[0][1] | &MOD};
|
BBSEL = {1'b0, !FETCH[0][1] | &MOD};
|
Line 1061... |
Line 1065... |
33: begin
|
33: begin
|
DISP16 = 1'b0;
|
DISP16 = 1'b0;
|
AEXT = 1'b0;
|
AEXT = 1'b0;
|
NOBP = 1'b1; // for RSSEL
|
NOBP = 1'b1; // for RSSEL
|
case(STAGE[1:0])
|
case(STAGE[1:0])
|
2'b00: begin // stage1, read ES:[DI] in FETCH[2:1], inc/dec DI
|
2'b00: begin // stage1, read ES:[DI] in FETCH[3:2], inc/dec DI
|
RASEL = 3'b111; // SI
|
RASEL = 3'b111; // SI
|
RSSEL = 2'b00; // ES
|
RSSEL = 2'b00; // ES
|
ALUOP = {4'b0100, FLAGS[10]};
|
ALUOP = {4'b0100, FLAGS[10]};
|
EAC = 4'b0101; // DI+DISP
|
EAC = 4'b0101; // DI+DISP
|
DISEL = 2'b11; // ALU 16bit
|
DISEL = 2'b11; // ALU 16bit
|
DOSEL = 2'b11; // read data to FETCH
|
DOSEL = 2'b11; // read data to FETCH
|
IFETCH = CPUStatus[4] && (~|CXZ || (CPUStatus[3] ^ TZF)); // REP & CX==0
|
IFETCH = RCXZ;//(~|CXZ || (CPUStatus[3] ^ TZF)); // REP & CX==0
|
MREQ = ~IFETCH;
|
MREQ = ~RCXZ;
|
WE[1:0] = IFETCH ? 2'b00 : 2'b11; // RASEL_HI, RASEL_LO
|
WE[1:0] = IFETCH ? 2'b00 : 2'b11; // RASEL_HI, RASEL_LO
|
end
|
end
|
2'b01: begin // stage2, read DS:[SI] in TMP16, inc/dec SI
|
2'b01: begin // stage2, read DS:[SI] in TMP16, inc/dec SI
|
RASEL = 3'b110; // DI
|
RASEL = 3'b110; // DI
|
ALUOP = {4'b0100, FLAGS[10]};
|
ALUOP = {4'b0100, FLAGS[10]};
|
EAC = 4'b0100; // SI+DISP
|
EAC = 4'b0100; // SI+DISP
|
DISEL = 2'b11; // ALU 16bit
|
DISEL = 2'b11; // ALU 16bit
|
IFETCH = 1'b0;
|
IFETCH = 1'b0;
|
WE[3:0] = 4'b1011; // RASEL_HI, RASEL_LO
|
WE[3:0] = 4'b1011; // RASEL_HI, RASEL_LO
|
end
|
end
|
2'b10: begin // stage3, compare TMP16 wit imm, set flags, dec CX
|
2'b10: begin // stage3, compare TMP16 with imm, set flags, dec CX
|
BASEL = 1'b0; // TMP16
|
BASEL = 1'b0; // TMP16
|
BBSEL = 2'b10; // imm
|
BBSEL = 2'b10; // imm
|
ISEL = 2'b01;
|
ISEL = 2'b01;
|
WE[4] = 1'b1; // flags
|
WE[4] = 1'b1; // flags
|
ALUOP = 5'b00111; // cmp
|
ALUOP = 5'b00111; // cmp
|
MREQ = 1'b0;
|
MREQ = 1'b0;
|
IFETCH = ~CPUStatus[4];
|
IFETCH = NRORCXLE1 | (CPUStatus[3] ^ CMPS);
|
DECCX = CPUStatus[4];
|
DECCX = CPUStatus[4];
|
ALUSTAGE = 1'b1;
|
ALUSTAGE = 1'b1;
|
REPINT = 1'b1;
|
REPINT = 1'b1;
|
end
|
end
|
endcase
|
endcase
|
Line 1099... |
Line 1103... |
end
|
end
|
// -------------------------------- (rep)scas --------------------------------
|
// -------------------------------- (rep)scas --------------------------------
|
34: begin
|
34: begin
|
DISP16 = 1'b0;
|
DISP16 = 1'b0;
|
AEXT = 1'b0;
|
AEXT = 1'b0;
|
NOBP = 1'b1; // for RSSEL (not really necesary, but with it the synthesis generates better speed)
|
|
if(!STAGE[0]) begin // stage1, read ES:[DI] in TMP16, inc/dec DI
|
if(!STAGE[0]) begin // stage1, read ES:[DI] in TMP16, inc/dec DI
|
RASEL = 3'b111; // DI
|
RASEL = 3'b111; // DI
|
RSSEL = 2'b00; // ES
|
RSSEL = 2'b00; // ES
|
ALUOP = {4'b0100, FLAGS[10]};
|
ALUOP = {4'b0100, FLAGS[10]};
|
EAC = 4'b0101; // DI+DISP
|
EAC = 4'b0101; // DI+DISP
|
DISEL = 2'b11; // ALU 16bit
|
DISEL = 2'b11; // ALU 16bit
|
IFETCH = CPUStatus[4] && (~|CXZ || (CPUStatus[3] ^ TZF)); // REP & CX==0
|
IFETCH = RCXZ;//(~|CXZ || (CPUStatus[3] ^ TZF)); // REP & CX==0
|
MREQ = ~IFETCH;
|
MREQ = ~RCXZ;
|
WE[3:0] = IFETCH ? 4'b0000 : 4'b1011; // TMP16, RASEL_HI, RASEL_LO
|
WE[3:0] = IFETCH ? 4'b0000 : 4'b1011; // TMP16, RASEL_HI, RASEL_LO
|
end else begin //stage2, compare AL/AX with TMP16, set flags, dec CX
|
end else begin //stage2, compare AL/AX with TMP16, set flags, dec CX
|
RASEL = 3'b000; // AL/AX
|
RASEL = 3'b000; // AL/AX
|
BBSEL = 2'b00; // TMP16
|
BBSEL = 2'b00; // TMP16
|
WE[4] = 1'b1; // flags
|
WE[4] = 1'b1; // flags
|
ALUOP = 5'b00111; // cmp
|
ALUOP = 5'b00111; // cmp
|
MREQ = 1'b0;
|
MREQ = 1'b0;
|
IFETCH = ~CPUStatus[4];
|
IFETCH = NRORCXLE1 | (CPUStatus[3] ^ SCAS);
|
DECCX = CPUStatus[4];
|
DECCX = CPUStatus[4];
|
REPINT = 1'b1;
|
REPINT = 1'b1;
|
end
|
end
|
ISIZE = IFETCH ? 1 : 0;
|
ISIZE = IFETCH ? 1 : 0;
|
end
|
end
|