yosys4gal/models/GAL16V8_reg.v
2024-05-03 21:44:22 -05:00

176 lines
3.9 KiB
Verilog

`default_nettype none
module GAL16V8_reg (
input wire clk,
input wire [7:0] in,
input wire oe_n,
inout wire [7:0] io
);
// Read in binary JEDEC file
reg [7:0] jed_bin_file [0:278];
initial $readmemh("GAL16V8_reg.hex", jed_bin_file);
// Linearize to a fuse map
wire [2193:0] fuses;
genvar i, j;
generate
for (i = 0; i < 274; i = i + 1) begin
for (j = 0; j < 8; j = j + 1) begin
assign fuses[8*i + j] = jed_bin_file[i + 4][j];
end
end
// Last couple bits
for (j = 0; j < 2; j = j + 1) begin
assign fuses[8*274 + j] = jed_bin_file[274 + 4][j];
end
endgenerate
// Extract useful fuses
wire syn_fuse, ac0_fuse;
assign syn_fuse = fuses[2192];
assign ac0_fuse = fuses[2193];
wire [7:0] xor_fuses;
assign xor_fuses = fuses[2055:2048];
wire [7:0] ac1_fuses;
assign ac1_fuses = fuses[2127:2120];
wire [255:0] sop_fuses [0:7];
wire [7:0] ptd_fuses [0:7];
generate
for (i = 0; i < 8; i = i + 1) begin
assign sop_fuses[i] = fuses[256*i +: 256];
assign ptd_fuses[i] = fuses[2128 + 8*i +: 8];
end
endgenerate
// Interleave in and feedback for SOP inputs
wire [7:0] feedback;
wire [15:0] interleaved;
generate
for (i = 0; i < 8; i = i + 1) begin
assign interleaved[2*i +: 2] = {feedback[i], in[i]};
end
endgenerate
// Generate GAL elements
generate
for (i = 0; i < 8; i = i + 1) begin
wire one_sop_out, sop_out;
// 1SOP
sop #(
.NUM_PRODUCTS(1),
.NUM_INPUTS(16)
) one_sop_inst (
.sop_fuses(sop_fuses[i][255:224]),
.ptd_fuses(ptd_fuses[i][0]),
.in(interleaved),
.out(one_sop_out)
);
// SOP
sop #(
.NUM_PRODUCTS(7),
.NUM_INPUTS(16)
) sop_inst (
.sop_fuses(sop_fuses[i][223:0]),
.ptd_fuses(ptd_fuses[i][7:1]),
.in(interleaved),
.out(sop_out)
);
// OLMC
olmc olmc_inst (
.xor_fuse(xor_fuses[i]),
.ac1_fuse(ac1_fuses[i]),
.sop(sop_out),
.one_sop(one_sop_out),
.clk(clk),
.oe_n(oe_n),
.io(io[i]),
.feedback(feedback[i])
);
end
endgenerate
// Simulation printing
initial begin
#1;
$display("SYN: %d, AC0: %d", syn_fuse, ac0_fuse);
$display("XOR: %b, AC1: %b", xor_fuses, ac1_fuses);
$display("Fuses: %x", fuses);
$display("sop0 %x", sop_fuses[0]);
$display("ptd0 %x", ptd_fuses[0]);
$display("sop1 %x", sop_fuses[1]);
$display("ptd1 %x", ptd_fuses[1]);
$display("sop2 %x", sop_fuses[2]);
$display("ptd2 %x", ptd_fuses[2]);
$display("sop3 %x", sop_fuses[3]);
$display("ptd3 %x", ptd_fuses[3]);
$display("sop4 %x", sop_fuses[4]);
$display("ptd4 %x", ptd_fuses[4]);
$display("sop5 %x", sop_fuses[5]);
$display("ptd5 %x", ptd_fuses[5]);
$display("sop6 %x", sop_fuses[6]);
$display("ptd6 %x", ptd_fuses[6]);
$display("sop7 %x", sop_fuses[7]);
$display("ptd7 %x", ptd_fuses[7]);
end
endmodule
module sop #(
parameter NUM_PRODUCTS = 7,
parameter NUM_INPUTS = 16
)(
input wire [2*NUM_INPUTS*NUM_PRODUCTS-1:0] sop_fuses,
input wire [NUM_PRODUCTS-1:0] ptd_fuses,
input wire [NUM_INPUTS-1:0] in,
output reg out
);
integer i, j;
reg match;
always @ (*) begin
out = 0;
for (i = 0; i < NUM_PRODUCTS; i = i + 1) begin
match = 1;
for (j = 0; j < NUM_INPUTS; j = j + 1) begin
if (!sop_fuses[2*NUM_INPUTS*i + 2*j + 0] && !in[j]) match = 0;
if (!sop_fuses[2*NUM_INPUTS*i + 2*j + 1] && in[j]) match = 0;
end
if (match && ptd_fuses[i]) out = 1;
end
end
endmodule
module olmc (
input wire xor_fuse,
input wire ac1_fuse,
input wire sop,
input wire one_sop,
input wire clk,
input wire oe_n,
inout wire io,
output wire feedback
);
// Internal combined SOP output with optional inversion
wire out;
assign out = (ac1_fuse ? sop : (sop || one_sop)) ^ xor_fuse;
reg reg_out;
always @ (posedge clk) begin
reg_out <= out;
end
assign feedback = ac1_fuse ? !reg_out : out;
assign io = ac1_fuse ? (one_sop ? !out : 1'bz) : // Combinational
(oe_n ? 1'bz : !reg_out); // Registered
endmodule