mirror of
https://github.com/hoglet67/AtomBusMon.git
synced 2025-01-02 23:32:02 +00:00
c045ebd10c
Change-Id: I97ca73690c7e1258a5b359260d695af25c21ca54
336 lines
9.3 KiB
Verilog
336 lines
9.3 KiB
Verilog
module MultiBootLoader
|
|
(
|
|
input clock,
|
|
input mode,
|
|
input [3:0] id,
|
|
output led1, // red
|
|
output led2, // trig 1
|
|
output led3, // trig 2
|
|
output ld1,
|
|
output ld2,
|
|
output ld3,
|
|
output ld4,
|
|
output ld5,
|
|
output ld6,
|
|
output ld7,
|
|
output ld8
|
|
);
|
|
|
|
reg [1:0] clk;
|
|
|
|
reg [15:0] icap_din;
|
|
reg icap_ce;
|
|
reg icap_wr;
|
|
|
|
reg [15:0] ff_icap_din_reversed;
|
|
reg ff_icap_ce;
|
|
reg ff_icap_wr;
|
|
|
|
reg [15:0] MBT_REBOOT = 16'h0000;
|
|
|
|
reg [24:0] counter;
|
|
|
|
ICAP_SPARTAN6 ICAP_SPARTAN6_inst
|
|
(
|
|
.BUSY (), // Busy output
|
|
.O (), // 16-bit data output
|
|
.CE (ff_icap_ce), // Clock enable input
|
|
.CLK (clk[0]), // Clock input
|
|
.I (ff_icap_din_reversed), // 16-bit data input
|
|
.WRITE (ff_icap_wr) // Write input
|
|
);
|
|
|
|
|
|
// -------------------------------------------------
|
|
// -- State Machine for ICAP_SPARTAN6 MultiBoot --
|
|
// -- sequence. --
|
|
// -------------------------------------------------
|
|
|
|
|
|
parameter
|
|
IDLE = 0,
|
|
SYNC_H = 1,
|
|
SYNC_L = 2,
|
|
|
|
CWD_H = 3,
|
|
CWD_L = 4,
|
|
|
|
GEN1_H = 5,
|
|
GEN1_L = 6,
|
|
|
|
GEN2_H = 7,
|
|
GEN2_L = 8,
|
|
|
|
GEN3_H = 9,
|
|
GEN3_L = 10,
|
|
|
|
GEN4_H = 11,
|
|
GEN4_L = 12,
|
|
|
|
GEN5_H = 13,
|
|
GEN5_L = 14,
|
|
|
|
NUL_H = 15,
|
|
NUL_L = 16,
|
|
|
|
MOD_H = 17,
|
|
MOD_L = 18,
|
|
|
|
HCO_H = 19,
|
|
HCO_L = 20,
|
|
|
|
RBT_H = 21,
|
|
RBT_L = 22,
|
|
|
|
NOOP_0 = 23,
|
|
NOOP_1 = 24,
|
|
NOOP_2 = 25,
|
|
NOOP_3 = 26;
|
|
|
|
|
|
reg [4:0] state = IDLE;
|
|
reg [4:0] next_state;
|
|
|
|
always @(MBT_REBOOT or state or id or mode)
|
|
begin: COMB
|
|
|
|
case (state)
|
|
|
|
IDLE:
|
|
begin
|
|
if (MBT_REBOOT==16'hffff)
|
|
begin
|
|
next_state = SYNC_H;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'hAA99; // Sync word part 1
|
|
end
|
|
else
|
|
begin
|
|
next_state = IDLE;
|
|
icap_ce = 1;
|
|
icap_wr = 1;
|
|
icap_din = 16'hFFFF; // Null data
|
|
end
|
|
end
|
|
|
|
SYNC_H:
|
|
begin
|
|
next_state = SYNC_L;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h5566; // Sync word part 2
|
|
end
|
|
|
|
SYNC_L:
|
|
begin
|
|
next_state = GEN1_H;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h3261; // Write to GENERAL_1 Register....
|
|
end
|
|
|
|
GEN1_H:
|
|
begin
|
|
next_state = GEN1_L;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
|
|
// Loader - 0300-0000
|
|
// Unknown Adapter - 0305-4000
|
|
// 6502 - 030A-8000 - mode 1 id 1110
|
|
// Z80 - 030F-C000 - mode x id 1101
|
|
// 65C02 - 0315-0000 - mode 0 id 1110 (future)
|
|
// 6809 - 031A-4000 - mode x id 1100 (future)
|
|
|
|
case ({mode, id})
|
|
5'b11110: icap_din = 16'h8000; // 6502
|
|
5'b11101: icap_din = 16'hC000; // Z80 (mode = 1)
|
|
5'b01101: icap_din = 16'hC000; // Z80 (mode = 0)
|
|
5'b01110: icap_din = 16'h0000; // 65C02
|
|
5'b11100: icap_din = 16'h4000; // 6809 (mode = 1)
|
|
5'b01100: icap_din = 16'h4000; // 6809 (mode = 0)
|
|
default: icap_din = 16'h4000; // Unknown Adapter
|
|
endcase
|
|
|
|
end
|
|
|
|
GEN1_L:
|
|
begin
|
|
next_state = GEN2_H;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h3281; // Write to GENERAL_2 Register....
|
|
end
|
|
|
|
GEN2_H:
|
|
begin
|
|
next_state = GEN2_L;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
|
|
case ({mode, id})
|
|
5'b11110: icap_din = 16'h030A; // 6502
|
|
5'b11101: icap_din = 16'h030F; // Z80 (mode = 1)
|
|
5'b01101: icap_din = 16'h030F; // Z80 (mode = 0)
|
|
5'b01110: icap_din = 16'h0315; // 65C02
|
|
5'b11100: icap_din = 16'h031A; // 6809 (mode = 1)
|
|
5'b01100: icap_din = 16'h031A; // 6809 (mode = 0)
|
|
default: icap_din = 16'h0305; // Unknown Adapter
|
|
endcase
|
|
|
|
end
|
|
|
|
GEN2_L:
|
|
begin
|
|
next_state = RBT_H;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h30A1; // Write to Command Register....
|
|
end
|
|
|
|
RBT_H:
|
|
begin
|
|
next_state = RBT_L;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h000E; // REBOOT Command issued.... value = 0x000E
|
|
end
|
|
|
|
RBT_L:
|
|
begin
|
|
next_state = NOOP_0;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h2000; // NOOP
|
|
end
|
|
|
|
NOOP_0:
|
|
begin
|
|
next_state = NOOP_1;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h2000; // NOOP
|
|
end
|
|
|
|
NOOP_1:
|
|
begin
|
|
next_state = NOOP_2;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h2000; // NOOP
|
|
end
|
|
|
|
NOOP_2:
|
|
begin
|
|
next_state = NOOP_3;
|
|
icap_ce = 0;
|
|
icap_wr = 0;
|
|
icap_din = 16'h2000; // NOOP
|
|
end
|
|
|
|
NOOP_3:
|
|
begin
|
|
next_state = IDLE;
|
|
icap_ce = 1;
|
|
icap_wr = 1;
|
|
icap_din = 16'h1111; // NULL value
|
|
end
|
|
|
|
default:
|
|
begin
|
|
next_state = IDLE;
|
|
icap_ce = 1;
|
|
icap_wr = 1;
|
|
icap_din = 16'h1111; // 16'h1111"
|
|
end
|
|
|
|
endcase
|
|
end
|
|
|
|
// Clock ICAP_SPARTAN6 and the state machine with clocks that are 90deg phase apart.
|
|
//
|
|
// This is an attempt to cure some reconfiguration unreliability.
|
|
//
|
|
// The problem is that ICAP_SPARTAN2 isn't treated by the Xilinx tools as a synchronous
|
|
// component, so when clocked off the same clock there can be timing issues.
|
|
//
|
|
// The below clocking patten runs the clock at 8MHz (half what it was before).
|
|
//
|
|
// It ensures there is plenty of setup and hold time margin for signals passing
|
|
// between ICAP_SPARTAN6 and the state machine, regardless of which clk edge is used
|
|
// ICAP_SPARTAN6.
|
|
//
|
|
// See this link for some related discussion:
|
|
// https://forums.xilinx.com/t5/Spartan-Family-FPGAs/20Mhz-limitation-for-ICAP-SPARTAN6/td-p/238060
|
|
//
|
|
// NOTE: I'm hedging here, as this bug is quite difficult to reproduce, and changing almost anything
|
|
// (e.g. connecting state to the test pins) causes the problem to go away.
|
|
//
|
|
// At worst this change should be harmless!
|
|
//
|
|
// Dave Banks - 18/07/2017
|
|
|
|
always@(posedge clock) begin
|
|
if (clk == 2'b00)
|
|
clk <= 2'b10;
|
|
else if (clk == 2'b10)
|
|
clk <= 2'b11;
|
|
else if (clk == 2'b11)
|
|
clk <= 2'b01;
|
|
else
|
|
clk <= 2'b00;
|
|
end
|
|
|
|
// Give a bit of delay before starting the state machine
|
|
always @(posedge clk[1]) begin
|
|
if (MBT_REBOOT == 16'hffff) begin
|
|
state <= next_state;
|
|
end else begin
|
|
MBT_REBOOT <= MBT_REBOOT + 1'b1;
|
|
state <= IDLE;
|
|
end
|
|
end
|
|
|
|
|
|
always @(posedge clk[1]) begin: ICAP_FF
|
|
// need to reverse bits to ICAP module since D0 bit is read first
|
|
ff_icap_din_reversed[0] <= icap_din[7];
|
|
ff_icap_din_reversed[1] <= icap_din[6];
|
|
ff_icap_din_reversed[2] <= icap_din[5];
|
|
ff_icap_din_reversed[3] <= icap_din[4];
|
|
ff_icap_din_reversed[4] <= icap_din[3];
|
|
ff_icap_din_reversed[5] <= icap_din[2];
|
|
ff_icap_din_reversed[6] <= icap_din[1];
|
|
ff_icap_din_reversed[7] <= icap_din[0];
|
|
ff_icap_din_reversed[8] <= icap_din[15];
|
|
ff_icap_din_reversed[9] <= icap_din[14];
|
|
ff_icap_din_reversed[10] <= icap_din[13];
|
|
ff_icap_din_reversed[11] <= icap_din[12];
|
|
ff_icap_din_reversed[12] <= icap_din[11];
|
|
ff_icap_din_reversed[13] <= icap_din[10];
|
|
ff_icap_din_reversed[14] <= icap_din[9];
|
|
ff_icap_din_reversed[15] <= icap_din[8];
|
|
ff_icap_ce <= icap_ce;
|
|
ff_icap_wr <= icap_wr;
|
|
end
|
|
|
|
always@(posedge clock) begin
|
|
counter <= counter + 1'b1;
|
|
end
|
|
|
|
assign led1 = 1'b1;
|
|
assign led2 = 1'b0;
|
|
assign led3 = 1'b0;
|
|
|
|
assign ld1 = counter[24];
|
|
assign ld2 = ~counter[24];
|
|
assign ld3 = 1'b0;
|
|
assign ld4 = state[4];
|
|
assign ld5 = state[3];
|
|
assign ld6 = state[2];
|
|
assign ld7 = state[1];
|
|
assign ld8 = state[0];
|
|
|
|
endmodule
|