mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-02-14 03:44:06 +00:00
197 lines
5.7 KiB
Systemverilog
197 lines
5.7 KiB
Systemverilog
module busControl( input s_clks Clks, input enT1, input enT4,
|
|
input permStart, permStop, iStop,
|
|
input aob0,
|
|
input isWrite, isByte, isRmc,
|
|
input busAvail,
|
|
output bgBlock,
|
|
output busAddrErr,
|
|
output waitBusCycle,
|
|
output busStarting, // Asserted during S0
|
|
output logic addrOe, // Asserted from S1 to the end, whole bus cycle except S0
|
|
output bciWrite, // Used for SSW on bus/addr error
|
|
|
|
input rDtack, BeDebounced, Vpai,
|
|
output ASn, output LDSn, output UDSn, eRWn);
|
|
|
|
reg rAS, rLDS, rUDS, rRWn;
|
|
assign ASn = rAS;
|
|
assign LDSn = rLDS;
|
|
assign UDSn = rUDS;
|
|
assign eRWn = rRWn;
|
|
|
|
reg dataOe;
|
|
|
|
reg bcPend;
|
|
reg isWriteReg, bciByte, isRmcReg, wendReg;
|
|
assign bciWrite = isWriteReg;
|
|
reg addrOeDelay;
|
|
reg isByteT4;
|
|
|
|
wire canStart, busEnd;
|
|
wire bcComplete, bcReset;
|
|
|
|
wire isRcmReset = bcComplete & bcReset & isRmcReg;
|
|
|
|
assign busAddrErr = aob0 & ~bciByte;
|
|
|
|
// Bus retry not really supported.
|
|
// It's BERR and HALT and not address error, and not read-modify cycle.
|
|
wire busRetry = ~busAddrErr & 1'b0;
|
|
|
|
enum int unsigned { SRESET = 0, SIDLE, S0, S2, S4, S6, SRMC_RES} busPhase, next;
|
|
|
|
always_ff @( posedge Clks.clk) begin
|
|
if( Clks.extReset)
|
|
busPhase <= SRESET;
|
|
else if( Clks.enPhi1)
|
|
busPhase <= next;
|
|
end
|
|
|
|
always_comb begin
|
|
case( busPhase)
|
|
SRESET: next = SIDLE;
|
|
SRMC_RES: next = SIDLE; // Single cycle special state when read phase of RMC reset
|
|
S0: next = S2;
|
|
S2: next = S4;
|
|
S4: next = busEnd ? S6 : S4;
|
|
S6: next = isRcmReset ? SRMC_RES : (canStart ? S0 : SIDLE);
|
|
SIDLE: next = canStart ? S0 : SIDLE;
|
|
default: next = SIDLE;
|
|
endcase
|
|
end
|
|
|
|
// Idle phase of RMC bus cycle. Might be better to just add a new state
|
|
wire rmcIdle = (busPhase == SIDLE) & ~ASn & isRmcReg;
|
|
|
|
assign canStart = (busAvail | rmcIdle) & (bcPend | permStart) & !busRetry & !bcReset;
|
|
|
|
wire busEnding = (next == SIDLE) | (next == S0);
|
|
|
|
assign busStarting = (busPhase == S0);
|
|
|
|
// term signal (DTACK, BERR, VPA, adress error)
|
|
assign busEnd = ~rDtack | iStop;
|
|
|
|
// bcComplete asserted on raising edge of S6 (together with SNC).
|
|
assign bcComplete = (busPhase == S6);
|
|
|
|
// Clear bus info latch on completion (regular or aborted) and no bus retry (and not PHI1).
|
|
// bciClear asserted half clock later on PHI2, and bci latches cleared async concurrently
|
|
wire bciClear = bcComplete & ~busRetry;
|
|
|
|
// Reset on reset or (berr & berrDelay & (not halt or rmc) & not 6800 & in bus cycle) (and not PHI1)
|
|
assign bcReset = Clks.extReset | (addrOeDelay & BeDebounced & Vpai);
|
|
|
|
// Enable uclock only on S6 (S8 on Bus Error) or not bciPermStop
|
|
assign waitBusCycle = wendReg & !bcComplete;
|
|
|
|
// Block Bus Grant when starting new bus cycle. But No need if AS already asserted (read phase of RMC)
|
|
// Except that when that RMC phase aborted on bus error, it's asserted one cycle later!
|
|
assign bgBlock = ((busPhase == S0) & ASn) | (busPhase == SRMC_RES);
|
|
|
|
always_ff @( posedge Clks.clk) begin
|
|
if( Clks.extReset) begin
|
|
addrOe <= 1'b0;
|
|
end
|
|
else if( Clks.enPhi2 & ( busPhase == S0)) // From S1, whole bus cycle except S0
|
|
addrOe <= 1'b1;
|
|
else if( Clks.enPhi1 & (busPhase == SRMC_RES))
|
|
addrOe <= 1'b0;
|
|
else if( Clks.enPhi1 & ~isRmcReg & busEnding)
|
|
addrOe <= 1'b0;
|
|
|
|
if( Clks.enPhi1)
|
|
addrOeDelay <= addrOe;
|
|
|
|
if( Clks.extReset) begin
|
|
rAS <= 1'b1;
|
|
rUDS <= 1'b1;
|
|
rLDS <= 1'b1;
|
|
rRWn <= 1'b1;
|
|
dataOe <= '0;
|
|
end
|
|
else begin
|
|
|
|
if( Clks.enPhi2 & isWriteReg & (busPhase == S2))
|
|
dataOe <= 1'b1;
|
|
else if( Clks.enPhi1 & (busEnding | (busPhase == SIDLE)) )
|
|
dataOe <= 1'b0;
|
|
|
|
if( Clks.enPhi1 & busEnding)
|
|
rRWn <= 1'b1;
|
|
else if( Clks.enPhi1 & isWriteReg) begin
|
|
// Unlike LDS/UDS Asserted even in address error
|
|
if( (busPhase == S0) & isWriteReg)
|
|
rRWn <= 1'b0;
|
|
end
|
|
|
|
// AS. Actually follows addrOe half cycle later!
|
|
if( Clks.enPhi1 & (busPhase == S0))
|
|
rAS <= 1'b0;
|
|
else if( Clks.enPhi2 & (busPhase == SRMC_RES)) // Bus error on read phase of RMC. Deasserted one cycle later
|
|
rAS <= 1'b1;
|
|
else if( Clks.enPhi2 & bcComplete & ~SRMC_RES)
|
|
if( ~isRmcReg) // Keep AS asserted on the IDLE phase of RMC
|
|
rAS <= 1'b1;
|
|
|
|
if( Clks.enPhi1 & (busPhase == S0)) begin
|
|
if( ~isWriteReg & !busAddrErr) begin
|
|
rUDS <= ~(~bciByte | ~aob0);
|
|
rLDS <= ~(~bciByte | aob0);
|
|
end
|
|
end
|
|
else if( Clks.enPhi1 & isWriteReg & (busPhase == S2) & !busAddrErr) begin
|
|
rUDS <= ~(~bciByte | ~aob0);
|
|
rLDS <= ~(~bciByte | aob0);
|
|
end
|
|
else if( Clks.enPhi2 & bcComplete) begin
|
|
rUDS <= 1'b1;
|
|
rLDS <= 1'b1;
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
// Bus cycle info latch. Needed because uinstr might change if the bus is busy and we must wait.
|
|
// Note that urom advances even on wait states. It waits *after* updating urom and nanorom latches.
|
|
// Even without wait states, ublocks of type ir (init reading) will not wait for bus completion.
|
|
// Originally latched on (permStart AND T1).
|
|
|
|
// Bus cycle info latch: isRead, isByte, read-modify-cycle, and permStart (bus cycle pending). Some previously latched on T4?
|
|
// permStop also latched, but unconditionally on T1
|
|
|
|
// Might make more sense to register this outside this module
|
|
always_ff @( posedge Clks.clk) begin
|
|
if( enT4) begin
|
|
isByteT4 <= isByte;
|
|
end
|
|
end
|
|
|
|
// Bus Cycle Info Latch
|
|
always_ff @( posedge Clks.clk) begin
|
|
if( Clks.pwrUp) begin
|
|
bcPend <= 1'b0;
|
|
wendReg <= 1'b0;
|
|
isWriteReg <= 1'b0;
|
|
bciByte <= 1'b0;
|
|
isRmcReg <= 1'b0;
|
|
end
|
|
|
|
else if( Clks.enPhi2 & (bciClear | bcReset)) begin
|
|
bcPend <= 1'b0;
|
|
wendReg <= 1'b0;
|
|
end
|
|
else begin
|
|
if( enT1 & permStart) begin
|
|
isWriteReg <= isWrite;
|
|
bciByte <= isByteT4;
|
|
isRmcReg <= isRmc & ~isWrite; // We need special case the end of the read phase only.
|
|
bcPend <= 1'b1;
|
|
end
|
|
if( enT1)
|
|
wendReg <= permStop;
|
|
end
|
|
end
|
|
|
|
endmodule
|