module QuatCorePipelineALUcontrol (input Bypass, input clk, input [7:0] DestAddr, input Csenior, input PM, input [15:0] D,input DestStall, output [2:0] AccMode, output cin, output BSigned, output [1:0] Bmode, output [1:0] Cmode, output Sena, output SrcStallReq, output Busy, output SBusy); wire isOurAddr = (DestAddr[7:5] == 3'b100)&(~DestStall); wire LatchNewCmd = isOurAddr & (isIdle | isAdd | finished); reg isLongCommand; reg DoClear; wire OpSign = DestAddr[0] & (DestAddr[1] | PM); //0 is '+', 1 is '-' wire CisSignedC = (DestAddr[3] == DestAddr[2]); reg isSignedC; reg FirstDivSign; reg AllowS; reg rBisSigned; always @(posedge clk) if (LatchNewCmd) begin AllowS <= isOurAddr & DestAddr[1] & DestAddr[0]; isSignedC <= CisSignedC; FirstDivSign <= OpSign ^ ((DestAddr[4] & CisSignedC & (isFirstDiv | MulFirst)) | (D[15] & (~DestAddr[4]) & (~DestAddr[3]) & DestAddr[2])); DoClear <= (DestAddr[1:0] == 2'b00); isLongCommand <= DestAddr[4]; rBisSigned <= (DestAddr[3:2] != 2'b10); end //first of all, 'state machine' localparam sIdle = 3'b000; localparam sDiv2 = 3'b001; localparam sFirstDiv = 3'b010; localparam sAdd = 3'b011; localparam sMult = 3'b100; reg [2:0] State = sIdle; wire isIdle = (State == sIdle); wire isFirstDiv = (State == sFirstDiv); wire isDiv2 = (State == sDiv2); wire isAdd = (State == sAdd); wire isMult = (State == sMult); reg MulFirst = 1'b0; always @(posedge clk) MulFirst <= isFirstDiv; wire finished; lpm_counter counter ( .clock (clk), .sclr (~isMult), .cout (finished) ); defparam counter.lpm_direction = "UP", counter.lpm_port_updown = "PORT_UNUSED", counter.lpm_type = "LPM_COUNTER", counter.lpm_width = 4; assign AccMode = isIdle? ((isOurAddr & (DestAddr[1:0] == 2'b00))? {1'b1, D[1:0]} : 3'b010) : (isFirstDiv | isDiv2)? {isLongCommand & DoClear, 1'b1, DoClear}: isAdd? 3'b000: {1'b0, ~Csenior, 1'b0}; //in 'clear' commands we either don't care of contents at first step (will clear it anyway), //or this is ZAcc command which sets one of consts. So we seek for this command //otherwise AccMode is idle. assign cin = FirstDivSign; //don't care at idle/FirstDiv/Div2, care at sAdd / sMult assign BSigned = rBisSigned | (~isFirstDiv); assign Bmode = (isIdle | isAdd | finished)? {1'b1, Bypass}: isFirstDiv? {1'b0, FirstDivSign} : {1'b0, isSignedC & MulFirst}; assign Cmode[1] = (isIdle | isAdd | finished)? isOurAddr & DestAddr[3] & (((~DestAddr[4])&(~DestAddr[2])&DestAddr[1])|(DestAddr[4]&DestAddr[2])) : isMult; assign Cmode[0] = ~isMult; assign Sena = (AllowS & isAdd) | isMult; assign SrcStallReq = isOurAddr & (~isIdle) & (~isAdd) & (~finished); assign Busy = ~isIdle; assign SBusy = Busy; wire CmdMoreThan1clk = isOurAddr & (DestAddr[4:2] != 3'b0_10); always @(posedge clk) State <= isIdle? (CmdMoreThan1clk? ((DestAddr[3:2] == 2'b11)? sDiv2 : sFirstDiv) : sIdle): isDiv2? sFirstDiv: isFirstDiv? (isLongCommand? sMult : sAdd): (isAdd | finished)? (CmdMoreThan1clk? ((DestAddr[3:2] == 2'b11)? sDiv2 : sFirstDiv): sIdle) : State; endmodule
И ещё попробовал синтезировать всё ядро в сборе. Со всеми подключёнными входами забастовал фиттер: Can't find fit. Это ничего страшного: когда я "вывожу наружу" слишком много широких шин (16-битную Data, 8-битные SrcAddr и DestAddr, Mem[], SP[] и пр. - в общем, потроха), так случается.
Когда отключил входы IN, GPU, SRAM, сработало нормально, синтезировалось в 667 ЛЭ и максимальную частоту 28,82 МГц.
Теперь, пожалуй, стряхну пыль с аффинного алгоритма - и опробую его для начала. В нём практически все возможности АЛУ проверяются, а отлаживать куда приятнее.