Skip to content

Commit

Permalink
Implemented remaining missing macrocell features. Still have to do so…
Browse files Browse the repository at this point in the history
…me global buffers.
azonenberg committed Jul 8, 2017
1 parent dcea3ae commit d466a3f
Showing 3 changed files with 332 additions and 58 deletions.
70 changes: 70 additions & 0 deletions hdl/xc2c-model/ConfigurableEdgeLatch.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
`default_nettype none
/***********************************************************************************************************************
* Copyright (C) 2016-2017 Andrew Zonenberg and contributors *
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General *
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for *
* more details. *
* *
* You should have received a copy of the GNU Lesser General Public License along with this program; if not, you may *
* find one here: *
* https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt *
* or you may search the http://www.gnu.org website for the version 2.1 license, or you may write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
**********************************************************************************************************************/
module ConfigurableEdgeLatch(
d, clk, sr, srval, q, pass_high
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// I/O declarations

input wire d;
input wire clk;
output wire q;
input wire sr;
input wire srval;

input wire pass_high;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The actual latches

//Transparent when high
reg pass_when_high;
always @(*) begin

//Pass data when high
if(clk)
pass_when_high <= d;

//Async set/reset
if(sr)
pass_when_high <= srval;

end

//Transparent when low
reg pass_when_low;
always @(*) begin

//Pass data when high
if(!clk)
pass_when_low <= d;

//Async set/reset
if(sr)
pass_when_low <= srval;

end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Output mux

assign q = pass_high ? pass_when_high : pass_when_low;

endmodule
97 changes: 71 additions & 26 deletions hdl/xc2c-model/XC2CDevice.v
Original file line number Diff line number Diff line change
@@ -207,9 +207,8 @@ module XC2CDevice(
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Global routing

//TODO: muxes for iob_in
wire[31:0] macrocell_to_zia;
wire[31:0] ibuf_to_zia = iob_in;
wire[31:0] ibuf_to_zia;

//Left side (FB2)
wire[39:0] left_zia_out;
@@ -276,27 +275,63 @@ module XC2CDevice(
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Global clock buffers
// Global buffers

/*
Fuse #12256 =
*/

//TODO: gclk enables
wire[2:0] global_ce = 3'b111;
reg[2:0] global_ce;
always @(*) begin
global_ce <= 3'b111;
end

//Clocks
wire[2:0] global_clk;
BUFGCE bufg_gclk0(.I(iob_in[20]), .O(global_clk[0]), .CE(global_ce[0]));
BUFGCE bufg_gclk1(.I(iob_in[21]), .O(global_clk[1]), .CE(global_ce[1]));
BUFGCE bufg_gclk2(.I(iob_in[22]), .O(global_clk[2]), .CE(global_ce[2]));

//TODO: gts enables (and inversions)
wire[2:0] global_te = 3'b111;
reg[3:0] global_tris;

always @(*) begin
global_tris <= 4'h0;
end

//TODO: gsr enables
reg global_sr_raw;
reg global_sr_en = 1'b1;
always @(*) begin
global_sr_raw <= 1'b0;
global_sr_en <= 1'b0;
end
wire global_sr;
BUFGCE bufg_gsr(.I(global_sr_raw), .O(global_sr), .CE(global_sr_en));

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Macrocells

wire[15:0] left_mc_to_obuf;
wire[15:0] right_mc_to_obuf;

wire left_cterm_clk;
wire right_cterm_clk;
BUFG bufg_left_ctc(.I(left_pterms[4]), .O(left_cterm_clk));
BUFG bufg_right_ctc(.I(right_pterms[4]), .O(right_cterm_clk));

//Global buffers
wire left_cterm_rst;
wire left_cterm_set;
wire left_cterm_oe = left_pterms[7];
wire right_cterm_rst;
wire right_cterm_set;
wire right_cterm_oe = right_pterms[7];

BUFG bufg_left_ctr(.I(left_pterms[5]), .O(left_cterm_rst));
BUFG bufg_right_ctr(.I(right_pterms[5]), .O(right_cterm_rst));
BUFG bufg_left_cts(.I(left_pterms[6]), .O(left_cterm_set));
BUFG bufg_right_cts(.I(right_pterms[6]), .O(right_cterm_set));

genvar g;
generate
for(g=0; g<16; g=g+1) begin : mcells
@@ -307,12 +342,24 @@ module XC2CDevice(
.pterm_b(left_pterms[g*3 + 9]),
.pterm_c(left_pterms[g*3 + 10]),
.or_term(left_orterms[g]),
.raw_ibuf(iob_in[g + 16]),

.cterm_clk(left_cterm_clk),
.global_clk(global_clk),

.global_sr(global_sr),
.cterm_reset(left_cterm_rst),
.cterm_set(left_cterm_set),
.cterm_oe(left_cterm_oe),
.global_tris(global_tris),

.config_done_rst(config_done_rst),

.mc_to_zia(macrocell_to_zia[g + 16]),
.mc_to_obuf(left_mc_to_obuf[g]),
.raw_ibuf(iob_in[g + 16])
.ibuf_to_zia(ibuf_to_zia[g + 16]),

.mc_to_obuf(iob_out[g + 16]),
.tristate_to_obuf(iob_t[g + 16])
);

XC2CMacrocell right(
@@ -321,12 +368,24 @@ module XC2CDevice(
.pterm_b(right_pterms[g*3 + 9]),
.pterm_c(right_pterms[g*3 + 10]),
.or_term(right_orterms[g]),
.raw_ibuf(iob_in[g]),

.cterm_clk(right_cterm_clk),
.global_clk(global_clk),

.global_sr(global_sr),
.cterm_reset(right_cterm_rst),
.cterm_set(right_cterm_set),
.cterm_oe(right_cterm_oe),
.global_tris(global_tris),

.config_done_rst(config_done_rst),

.mc_to_zia(macrocell_to_zia[g]),
.mc_to_obuf(right_mc_to_obuf[g]),
.raw_ibuf(iob_in[g])
.ibuf_to_zia(ibuf_to_zia[g]),

.mc_to_obuf(iob_out[g]),
.tristate_to_obuf(iob_t[g])
);

end
@@ -335,21 +394,7 @@ module XC2CDevice(
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Debug stuff

//Tristate all pins except our outputs (6:3)
assign iob_t[31:7] = 25'h1ffffff;
assign iob_t[6:3] = 4'h0;
assign iob_t[2:0] = 3'h7;

//Drive all unused outputs to 0, then hook up our outputs
//Should be X, !X, X, X
assign iob_out[31:7] = 25'h0;
assign iob_out[6] = right_mc_to_obuf[6];
assign iob_out[5] = right_mc_to_obuf[5];
assign iob_out[4] = right_mc_to_obuf[4];
assign iob_out[3] = right_mc_to_obuf[3];
assign iob_out[2:0] = 3'h0;

//Helper to keep stuff from getting optimized out
assign dbgout = ^macrocell_to_zia ^ ^right_mc_to_obuf ^ ^left_mc_to_obuf;
assign dbgout = ^macrocell_to_zia ^ ^iob_out ^ ^iob_t;

endmodule
223 changes: 191 additions & 32 deletions hdl/xc2c-model/XC2CMacrocell.v
Original file line number Diff line number Diff line change
@@ -21,31 +21,47 @@ module XC2CMacrocell(
pterm_a, pterm_b, pterm_c,
or_term,
cterm_clk, global_clk,
mc_to_zia, mc_to_obuf,
mc_to_zia, ibuf_to_zia, mc_to_obuf,
tristate_to_obuf,
raw_ibuf,
config_done_rst
config_done_rst, global_sr, cterm_reset, cterm_set, cterm_oe, global_tris
);

/*
UNIMPLEMENTED FEATURES (WONTFIX, the emulator doesn't have a pad ring so these make no sense)
* Config bit 10: Schmitt trigger on input
* Config bit 2: Termination
* Config bit 1: Slew rate
*/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// I/O declarations

input wire[26:0] config_bits;
input wire[26:0] config_bits;

input wire pterm_a;
input wire pterm_b;
input wire pterm_c;

input wire pterm_a;
input wire pterm_b;
input wire pterm_c;
input wire or_term;

input wire or_term;
input wire cterm_clk;
input wire[2:0] global_clk;

input wire cterm_clk;
input wire[2:0] global_clk;
output reg mc_to_zia;
output reg mc_to_obuf;
output reg ibuf_to_zia;

output reg mc_to_zia;
output reg mc_to_obuf;
output reg tristate_to_obuf;

input wire raw_ibuf;
input wire raw_ibuf;

input wire config_done_rst;
input wire config_done_rst;
input wire global_sr;
input wire cterm_reset;
input wire cterm_set;
input wire cterm_oe;
input wire[3:0] global_tris;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Macrocell XOR
@@ -65,8 +81,6 @@ module XC2CMacrocell(
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FF input muxing

//TODO: implement latch mode

reg dff_imux;

reg dff_in;
@@ -129,7 +143,27 @@ module XC2CMacrocell(
dff_srval <= !config_bits[0];
end

//TODO: set/reset inputs
//DFF reset
else if(
( (config_bits[21:20] == 2'b00) && pterm_a ) ||
( (config_bits[21:20] == 2'b01) && global_sr ) ||
( (config_bits[21:20] == 2'b00) && cterm_reset )
) begin
dff_sr <= 1;
dff_srval <= 0;
end

//DFF set
else if(
( (config_bits[19:18] == 2'b00) && pterm_a ) ||
( (config_bits[19:18] == 2'b01) && global_sr ) ||
( (config_bits[19:18] == 2'b00) && cterm_set )
) begin
dff_sr <= 1;
dff_srval <= 1;
end

//Nope, not setting or resetting
else begin
dff_sr <= 0;
dff_srval <= 0;
@@ -208,54 +242,179 @@ module XC2CMacrocell(
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FF output muxing
// Macrocell latch

wire mc_latch_ctc;
ConfigurableEdgeLatch l_ctc(
.d(dff_in),
.clk(cterm_clk),
.sr(dff_sr),
.srval(dff_srval),
.q(mc_latch_ctc),
.pass_high(!config_bits[25])
);

wire mc_latch_ptc;
ConfigurableEdgeLatch l_ptc(
.d(dff_in),
.clk(pterm_c),
.sr(dff_sr),
.srval(dff_srval),
.q(mc_latch_ptc),
.pass_high(!config_bits[25])
);

wire mc_latch_gck0;
ConfigurableEdgeLatch l_gck0(
.d(dff_in),
.clk(global_clk[0]),
.sr(dff_sr),
.srval(dff_srval),
.q(mc_latch_gck0),
.pass_high(!config_bits[25])
);

wire mc_latch_gck1;
ConfigurableEdgeLatch l_gck1(
.d(dff_in),
.clk(global_clk[1]),
.sr(dff_sr),
.srval(dff_srval),
.q(mc_latch_gck1),
.pass_high(!config_bits[25])
);

wire mc_latch_gck2;
ConfigurableEdgeLatch l_gck2(
.d(dff_in),
.clk(global_clk[2]),
.sr(dff_sr),
.srval(dff_srval),
.q(mc_latch_gck2),
.pass_high(!config_bits[25])
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Storage element output muxing

//Final clock output mux
reg mc_dff_muxed;
reg mc_latch_muxed;
reg mc_storage_muxed;
always @(*) begin

case(config_bits[24:23])
0: mc_dff_muxed <= mc_dff_gck0;
1: mc_dff_muxed <= mc_dff_gck2;
2: mc_dff_muxed <= mc_dff_gck1;
0: begin
mc_dff_muxed <= mc_dff_gck0;
mc_latch_muxed <= mc_latch_gck0;
end
1: begin
mc_dff_muxed <= mc_dff_gck2;
mc_latch_muxed <= mc_latch_gck2;
end
2: begin
mc_dff_muxed <= mc_dff_gck1;
mc_latch_muxed <= mc_latch_gck1;
end
3: begin
if(config_bits[26])
if(config_bits[26]) begin
mc_dff_muxed <= mc_dff_ctc;
else
mc_latch_muxed <= mc_latch_ctc;
end
else begin
mc_dff_muxed <= mc_dff_ptc;
mc_latch_muxed <= mc_latch_ptc;
end
end
endcase

//Take output from latch
if(config_bits[17:16] == 2'b01)
mc_storage_muxed <= mc_latch_muxed;

//Nope, output comes from DFF
else
mc_storage_muxed <= mc_dff_muxed;

end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Final output muxing

//TODO: mux for bit 15 (ibuf/mc flipflop)

always @(*) begin

//Enable for macrocell->ZIA driver (active low so we're powered down when device is blank)
if(!config_bits[12]) begin

//See where macrocell->ZIA driver should go
//See where macrocell->ZIA driver should come from
if(config_bits[13])
mc_to_zia <= mc_dff_muxed;
mc_to_zia <= mc_storage_muxed;
else
mc_to_zia <= xor_out;
mc_to_zia <= xor_out;

end

//Output driver powered down, feed a constant zero into the ZIA to prevent spurious toggles
else
mc_to_zia <= 1'b0;
mc_to_zia <= 1'b0;

//Mux for CGND
if(config_bits[6:3] == 4'b1110)
mc_to_obuf <= 1'b0;
else begin

//Mux for pad driver
if(config_bits[7])
mc_to_obuf <= xor_out;
else
mc_to_obuf <= mc_storage_muxed;

end

//Mux for pad driver
if(config_bits[7])
mc_to_obuf <= xor_out;
//Enable for input->ZIA driver (active low so we're powered down when device is blank)
if(!config_bits[14]) begin

//See where input->ZIA driver should come from
if(config_bits[15])
ibuf_to_zia <= mc_storage_muxed;
else
ibuf_to_zia <= raw_ibuf;

end

//Output driver powered down, feed a constant zero into the ZIA to prevent spurious toggles
else
mc_to_obuf <= mc_dff_muxed;
ibuf_to_zia <= 1'b0;

end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Tri-state control

always @(*) begin

case(config_bits[6:3])

4'b0000: tristate_to_obuf <= 1'b0; //Push-pull output, always enabled (not tristated)
4'b0001: tristate_to_obuf <= mc_to_obuf; //Open drain (tristating any time we drive high)
4'b0010: tristate_to_obuf <= global_tris[1]; //Tri-state output (using GTS1)
//4'b0011: //Unknown
4'b0100: tristate_to_obuf <= pterm_b; //Tri-state output (using PTB)
//4'b0101: //Unknown
4'b0110: tristate_to_obuf <= global_tris[3]; //Tri-state output (using GTS3)
//4'b0111: //Unknown
4'b1000: tristate_to_obuf <= cterm_oe; //Tri-state output (using CTE)
//4'b1001: //Unknown
4'b1010: tristate_to_obuf <= global_tris[2]; //Tri-state output (using GTS2)
//4'b1011: //Unknown
4'b1100: tristate_to_obuf <= global_tris[0]; //Tri-state output (using GTS0)
//4'b1101: //Unknown
4'b1110: tristate_to_obuf <= 1'b0; //CGND, always enabled (not tristated)
4'b1111: tristate_to_obuf <= 1'b1; //Input/unused (always tristated)

default: tristate_to_obuf <= 1'b1; //unknown, float the output

endcase
end

endmodule

0 comments on commit d466a3f

Please sign in to comment.