2013-10-28 13:19:25 +00:00

1855 lines
48 KiB
Verilog

`define YES
`include "revision.v"
module lfsre(
input clk,
output reg [16:0] lfsr);
wire d0;
xnor(d0,lfsr[16],lfsr[13]);
always @(posedge clk) begin
lfsr <= {lfsr[15:0],d0};
end
endmodule
module oldram256x1s(
input d,
input we,
input wclk,
input [7:0] a,
output o);
wire sel0 = (a[7:6] == 0);
wire o0;
RAM64X1S r0(.O(o0), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .A5(a[5]), .D(d), .WCLK(wclk), .WE(sel0 & we));
wire sel1 = (a[7:6] == 1);
wire o1;
RAM64X1S r1(.O(o1), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .A5(a[5]), .D(d), .WCLK(wclk), .WE(sel1 & we));
wire sel2 = (a[7:6] == 2);
wire o2;
RAM64X1S r2(.O(o2), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .A5(a[5]), .D(d), .WCLK(wclk), .WE(sel2 & we));
wire sel3 = (a[7:6] == 3);
wire o3;
RAM64X1S r3(.O(o3), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .A5(a[5]), .D(d), .WCLK(wclk), .WE(sel3 & we));
assign o = (a[7] == 0) ? ((a[6] == 0) ? o0 : o1) : ((a[6] == 0) ? o2 : o3);
endmodule
module ring64(
input clk,
input i,
output o);
wire o0, o1, o2;
SRL16E ring0( .CLK(clk), .CE(1), .D(i), .A0(1), .A1(1), .A2(1), .A3(1), .Q(o0));
SRL16E ring1( .CLK(clk), .CE(1), .D(o0), .A0(1), .A1(1), .A2(1), .A3(1), .Q(o1));
SRL16E ring2( .CLK(clk), .CE(1), .D(o1), .A0(1), .A1(1), .A2(1), .A3(1), .Q(o2));
SRL16E ring3( .CLK(clk), .CE(1), .D(o2), .A0(1), .A1(1), .A2(1), .A3(1), .Q(o));
endmodule
module ram256x1s(
input d,
input we,
input wclk,
input [7:0] a,
output o);
wire [1:0] rsel = a[7:6];
wire [3:0] oo;
genvar i;
generate
for (i = 0; i < 4; i=i+1) begin : ramx
RAM64X1S r0(.O(oo[i]), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .A5(a[5]), .D(d), .WCLK(wclk), .WE((rsel == i) & we));
end
endgenerate
assign o = oo[rsel];
endmodule
module ram448x1s(
input d,
input we,
input wclk,
input [8:0] a,
output o);
wire [2:0] rsel = a[8:6];
wire [7:0] oo;
genvar i;
generate
for (i = 0; i < 7; i=i+1) begin : ramx
RAM64X1S r0(.O(oo[i]), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .A5(a[5]), .D(d), .WCLK(wclk), .WE((rsel == i) & we));
end
endgenerate
assign o = oo[rsel];
endmodule
module ram400x1s(
input d,
input we,
input wclk,
input [8:0] a,
output o);
wire [2:0] rsel = a[8:6];
wire [6:0] oo;
genvar i;
generate
for (i = 0; i < 6; i=i+1) begin : ramx
RAM64X1S r0(.O(oo[i]), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .A5(a[5]), .D(d), .WCLK(wclk), .WE((rsel == i) & we));
end
endgenerate
RAM16X1S r6(.O(oo[6]), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .D(d), .WCLK(wclk), .WE((rsel == 6) & we));
assign o = oo[rsel];
endmodule
module ram256x8s(
input [7:0] d,
input we,
input wclk,
input [7:0] a,
output [7:0] o);
genvar i;
generate
for (i = 0; i < 8; i=i+1) begin : ramx
ram256x1s ramx(
.d(d[i]),
.we(we),
.wclk(wclk),
.a(a),
.o(o[i]));
end
endgenerate
endmodule
module ram32x8s(
input [7:0] d,
input we,
input wclk,
input [4:0] a,
output [7:0] o);
genvar i;
generate
for (i = 0; i < 8; i=i+1) begin : ramx
RAM32X1S r0(.O(o[i]), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .D(d[i]), .WCLK(wclk), .WE(we));
end
endgenerate
endmodule
module ram64x8s(
input [7:0] d,
input we,
input wclk,
input [5:0] a,
output [7:0] o);
genvar i;
generate
for (i = 0; i < 8; i=i+1) begin : ramx
RAM64X1S r0(.O(o[i]), .A0(a[0]), .A1(a[1]), .A2(a[2]), .A3(a[3]), .A4(a[4]), .A5(a[5]), .D(d[i]), .WCLK(wclk), .WE(we));
end
endgenerate
endmodule
module mRAM32X1D(
input D,
input WE,
input WCLK,
input A0, // port A
input A1,
input A2,
input A3,
input A4,
input DPRA0, // port B
input DPRA1,
input DPRA2,
input DPRA3,
input DPRA4,
output DPO, // port A out
output SPO); // port B out
parameter INIT = 32'b0;
wire hDPO;
wire lDPO;
wire hSPO;
wire lSPO;
RAM16X1D
#( .INIT(INIT[15:0]) )
lo(
.D(D),
.WE(WE & !A4),
.WCLK(WCLK),
.A0(A0),
.A1(A1),
.A2(A2),
.A3(A3),
.DPRA0(DPRA0),
.DPRA1(DPRA1),
.DPRA2(DPRA2),
.DPRA3(DPRA3),
.DPO(lDPO),
.SPO(lSPO));
RAM16X1D
#( .INIT(INIT[31:16]) )
hi(
.D(D),
.WE(WE & A4),
.WCLK(WCLK),
.A0(A0),
.A1(A1),
.A2(A2),
.A3(A3),
.DPRA0(DPRA0),
.DPRA1(DPRA1),
.DPRA2(DPRA2),
.DPRA3(DPRA3),
.DPO(hDPO),
.SPO(hSPO));
assign DPO = DPRA4 ? hDPO : lDPO;
assign SPO = A4 ? hSPO : lSPO;
endmodule
module mRAM64X1D(
input D,
input WE,
input WCLK,
input A0, // port A
input A1,
input A2,
input A3,
input A4,
input A5,
input DPRA0, // port B
input DPRA1,
input DPRA2,
input DPRA3,
input DPRA4,
input DPRA5,
output DPO, // port A out
output SPO); // port B out
parameter INIT = 64'b0;
wire hDPO;
wire lDPO;
wire hSPO;
wire lSPO;
mRAM32X1D
#( .INIT(INIT[31:0]) )
lo(
.D(D),
.WE(WE & !A5),
.WCLK(WCLK),
.A0(A0),
.A1(A1),
.A2(A2),
.A3(A3),
.A4(A4),
.DPRA0(DPRA0),
.DPRA1(DPRA1),
.DPRA2(DPRA2),
.DPRA3(DPRA3),
.DPRA4(DPRA4),
.DPO(lDPO),
.SPO(lSPO));
mRAM32X1D
#( .INIT(INIT[63:32]) )
hi(
.D(D),
.WE(WE & A5),
.WCLK(WCLK),
.A0(A0),
.A1(A1),
.A2(A2),
.A3(A3),
.A4(A4),
.DPRA0(DPRA0),
.DPRA1(DPRA1),
.DPRA2(DPRA2),
.DPRA3(DPRA3),
.DPRA4(DPRA4),
.DPO(hDPO),
.SPO(hSPO));
assign DPO = DPRA5 ? hDPO : lDPO;
assign SPO = A5 ? hSPO : lSPO;
endmodule
module mRAM128X1D(
input D,
input WE,
input WCLK,
input A0, // port A
input A1,
input A2,
input A3,
input A4,
input A5,
input A6,
input DPRA0, // port B
input DPRA1,
input DPRA2,
input DPRA3,
input DPRA4,
input DPRA5,
input DPRA6,
output DPO, // port A out
output SPO); // port B out
parameter INIT = 128'b0;
wire hDPO;
wire lDPO;
wire hSPO;
wire lSPO;
mRAM64X1D
#( .INIT(INIT[63:0]) )
lo(
.D(D),
.WE(WE & !A6),
.WCLK(WCLK),
.A0(A0),
.A1(A1),
.A2(A2),
.A3(A3),
.A4(A4),
.A5(A5),
.DPRA0(DPRA0),
.DPRA1(DPRA1),
.DPRA2(DPRA2),
.DPRA3(DPRA3),
.DPRA4(DPRA4),
.DPRA5(DPRA5),
.DPO(lDPO),
.SPO(lSPO));
mRAM64X1D
#( .INIT(INIT[127:64]) )
hi(
.D(D),
.WE(WE & A6),
.WCLK(WCLK),
.A0(A0),
.A1(A1),
.A2(A2),
.A3(A3),
.A4(A4),
.A5(A5),
.DPRA0(DPRA0),
.DPRA1(DPRA1),
.DPRA2(DPRA2),
.DPRA3(DPRA3),
.DPRA4(DPRA4),
.DPRA5(DPRA5),
.DPO(hDPO),
.SPO(hSPO));
assign DPO = DPRA6 ? hDPO : lDPO;
assign SPO = A6 ? hSPO : lSPO;
endmodule
module mRAM256X1D(
input D,
input WE,
input WCLK,
input A0, // port A
input A1,
input A2,
input A3,
input A4,
input A5,
input A6,
input A7,
input DPRA0, // port B
input DPRA1,
input DPRA2,
input DPRA3,
input DPRA4,
input DPRA5,
input DPRA6,
input DPRA7,
output DPO, // port A out
output SPO); // port B out
wire hDPO;
wire lDPO;
wire hSPO;
wire lSPO;
mRAM128X1D
lo(
.D(D),
.WE(WE & !A7),
.WCLK(WCLK),
.A0(A0),
.A1(A1),
.A2(A2),
.A3(A3),
.A4(A4),
.A5(A5),
.A6(A6),
.DPRA0(DPRA0),
.DPRA1(DPRA1),
.DPRA2(DPRA2),
.DPRA3(DPRA3),
.DPRA4(DPRA4),
.DPRA5(DPRA5),
.DPRA6(DPRA6),
.DPO(lDPO),
.SPO(lSPO));
mRAM128X1D
hi(
.D(D),
.WE(WE & A7),
.WCLK(WCLK),
.A0(A0),
.A1(A1),
.A2(A2),
.A3(A3),
.A4(A4),
.A5(A5),
.A6(A6),
.DPRA0(DPRA0),
.DPRA1(DPRA1),
.DPRA2(DPRA2),
.DPRA3(DPRA3),
.DPRA4(DPRA4),
.DPRA5(DPRA5),
.DPRA6(DPRA6),
.DPO(hDPO),
.SPO(hSPO));
assign DPO = DPRA7 ? hDPO : lDPO;
assign SPO = A7 ? hSPO : lSPO;
endmodule
module ram32x8d(
input [7:0] ad,
input wea,
input wclk,
input [4:0] a,
input [4:0] b,
output [7:0] ao,
output [7:0] bo
);
genvar i;
generate
for (i = 0; i < 8; i=i+1) begin : ramx
mRAM32X1D ramx(
.D(ad[i]),
.WE(wea),
.WCLK(wclk),
.A0(a[0]),
.A1(a[1]),
.A2(a[2]),
.A3(a[3]),
.A4(a[4]),
.DPRA0(b[0]),
.DPRA1(b[1]),
.DPRA2(b[2]),
.DPRA3(b[3]),
.DPRA4(b[4]),
.SPO(ao[i]),
.DPO(bo[i]));
end
endgenerate
endmodule
module ram64x8d(
input [7:0] ad,
input wea,
input wclk,
input [5:0] a,
input [5:0] b,
output [7:0] ao,
output [7:0] bo
);
genvar i;
generate
for (i = 0; i < 8; i=i+1) begin : ramx
mRAM64X1D ramx(
.D(ad[i]),
.WE(wea),
.WCLK(wclk),
.A0(a[0]),
.A1(a[1]),
.A2(a[2]),
.A3(a[3]),
.A4(a[4]),
.A5(a[5]),
.DPRA0(b[0]),
.DPRA1(b[1]),
.DPRA2(b[2]),
.DPRA3(b[3]),
.DPRA4(b[4]),
.DPRA5(b[5]),
.SPO(ao[i]),
.DPO(bo[i]));
end
endgenerate
endmodule
// Same but latched read port, for CPU
module ram32x8rd(
input wclk,
input [15:0] ad,
input wea,
input [4:0] a,
input [4:0] b,
output reg [15:0] ao,
output reg [15:0] bo
);
wire [15:0] _ao;
wire [15:0] _bo;
always @(posedge wclk)
begin
ao <= _ao;
bo <= _bo;
end
genvar i;
generate
for (i = 0; i < 16; i=i+1) begin : ramx
mRAM32X1D ramx(
.D(ad[i]),
.WE(wea),
.WCLK(wclk),
.A0(a[0]),
.A1(a[1]),
.A2(a[2]),
.A3(a[3]),
.A4(a[4]),
.DPRA0(b[0]),
.DPRA1(b[1]),
.DPRA2(b[2]),
.DPRA3(b[3]),
.DPRA4(b[4]),
.SPO(_ao[i]),
.DPO(_bo[i]));
end
endgenerate
endmodule
module ram128x8rd(
input wclk,
input [15:0] ad,
input wea,
input [6:0] a,
input [6:0] b,
output reg [15:0] ao,
output reg [15:0] bo
);
wire [15:0] _ao;
wire [15:0] _bo;
always @(posedge wclk)
begin
ao <= _ao;
bo <= _bo;
end
genvar i;
generate
for (i = 0; i < 8; i=i+1) begin : ramx
mRAM128X1D ramx(
.D(ad[i]),
.WE(wea),
.WCLK(wclk),
.A0(a[0]),
.A1(a[1]),
.A2(a[2]),
.A3(a[3]),
.A4(a[4]),
.A5(a[5]),
.A6(a[6]),
.DPRA0(b[0]),
.DPRA1(b[1]),
.DPRA2(b[2]),
.DPRA3(b[3]),
.DPRA4(b[4]),
.DPRA5(b[5]),
.DPRA6(b[6]),
.SPO(_ao[i]),
.DPO(_bo[i]));
end
endgenerate
endmodule
module ram256x8rd(
input wclk,
input [7:0] ad,
input wea,
input [7:0] a,
input [7:0] b,
output reg [7:0] ao,
output reg [7:0] bo
);
wire [7:0] _ao;
wire [7:0] _bo;
always @(posedge wclk)
begin
ao <= _ao;
bo <= _bo;
end
genvar i;
generate
for (i = 0; i < 8; i=i+1) begin : ramx
mRAM256X1D ramx(
.D(ad[i]),
.WE(wea),
.WCLK(wclk),
.A0(a[0]),
.A1(a[1]),
.A2(a[2]),
.A3(a[3]),
.A4(a[4]),
.A5(a[5]),
.A6(a[6]),
.A7(a[7]),
.DPRA0(b[0]),
.DPRA1(b[1]),
.DPRA2(b[2]),
.DPRA3(b[3]),
.DPRA4(b[4]),
.DPRA5(b[5]),
.DPRA6(b[6]),
.DPRA7(b[7]),
.SPO(_ao[i]),
.DPO(_bo[i]));
end
endgenerate
endmodule
module ram448x9s(
input [8:0] d,
input we,
input wclk,
input [8:0] a,
output [8:0] o);
genvar i;
generate
for (i = 0; i < 9; i=i+1) begin : ramx
ram448x1s ramx(
.d(d[i]),
.we(we),
.wclk(wclk),
.a(a),
.o(o[i]));
end
endgenerate
endmodule
module ram400x9s(
input [8:0] d,
input we,
input wclk,
input [8:0] a,
output [8:0] o);
genvar i;
generate
for (i = 0; i < 9; i=i+1) begin : ramx
ram400x1s ramx(
.d(d[i]),
.we(we),
.wclk(wclk),
.a(a),
.o(o[i]));
end
endgenerate
endmodule
module ram400x8s(
input [7:0] d,
input we,
input wclk,
input [8:0] a,
output [7:0] o);
genvar i;
generate
for (i = 0; i < 8; i=i+1) begin : ramx
ram400x1s ramx(
.d(d[i]),
.we(we),
.wclk(wclk),
.a(a),
.o(o[i]));
end
endgenerate
endmodule
module ram400x7s(
input [6:0] d,
input we,
input wclk,
input [8:0] a,
output [6:0] o);
genvar i;
generate
for (i = 0; i < 7; i=i+1) begin : ramx
ram400x1s ramx(
.d(d[i]),
.we(we),
.wclk(wclk),
.a(a),
.o(o[i]));
end
endgenerate
endmodule
// SPI can be many things, so to be clear, this implementation:
// MSB first
// CPOL 0, leading edge when SCK rises
// CPHA 0, sample on leading, setup on trailing
module SPI_memory(
input clk,
input SCK, input MOSI, output MISO, input SSEL,
output wire [15:0] raddr, // read address
output reg [15:0] waddr, // write address
output reg [7:0] data_w,
input [7:0] data_r,
output reg we,
output reg re,
output mem_clk
);
reg [15:0] paddr;
reg [4:0] count;
wire [4:0] _count = (count == 23) ? 16 : (count + 1);
assign mem_clk = clk;
// sync SCK to the FPGA clock using a 3-bits shift register
reg [2:0] SCKr; always @(posedge clk) SCKr <= {SCKr[1:0], SCK};
wire SCK_risingedge = (SCKr[2:1]==2'b01); // now we can detect SCK rising edges
wire SCK_fallingedge = (SCKr[2:1]==2'b10); // and falling edges
// same thing for SSEL
reg [2:0] SSELr; always @(posedge clk) SSELr <= {SSELr[1:0], SSEL};
wire SSEL_active = ~SSELr[1]; // SSEL is active low
wire SSEL_startmessage = (SSELr[2:1]==2'b10); // message starts at falling edge
wire SSEL_endmessage = (SSELr[2:1]==2'b01); // message stops at rising edge
// and for MOSI
reg [1:0] MOSIr; always @(posedge clk) MOSIr <= {MOSIr[0], MOSI};
wire MOSI_data = MOSIr[1];
assign raddr = (count[4] == 0) ? {paddr[14:0], MOSI} : paddr;
always @(posedge clk)
begin
if (~SSEL_active) begin
count <= 0;
re <= 0;
we <= 0;
end else
if (SCK_risingedge) begin
if (count[4] == 0) begin
we <= 0;
paddr <= raddr;
re <= (count == 15);
end else begin
data_w <= {data_w[6:0], MOSI_data};
if (count == 23) begin
we <= paddr[15];
re <= !paddr[15];
waddr <= paddr;
paddr <= paddr + 1;
end else begin
we <= 0;
re <= 0;
end
end
count <= _count;
end
if (SCK_fallingedge) begin
re <= 0;
we <= 0;
end
end
reg readbit;
always @*
begin
case (count[2:0])
3'd0: readbit <= data_r[7];
3'd1: readbit <= data_r[6];
3'd2: readbit <= data_r[5];
3'd3: readbit <= data_r[4];
3'd4: readbit <= data_r[3];
3'd5: readbit <= data_r[2];
3'd6: readbit <= data_r[1];
3'd7: readbit <= data_r[0];
endcase
end
assign MISO = readbit;
endmodule
// This is a Delta-Sigma Digital to Analog Converter
`define MSBI 12 // Most significant Bit of DAC input, 12 means 13-bit
module dac(DACout, DACin, Clk, Reset);
output DACout; // This is the average output that feeds low pass filter
reg DACout; // for optimum performance, ensure that this ff is in IOB
input [`MSBI:0] DACin; // DAC input (excess 2**MSBI)
input Clk;
input Reset;
reg [`MSBI+2:0] DeltaAdder; // Output of Delta adder
reg [`MSBI+2:0] SigmaAdder; // Output of Sigma adder
reg [`MSBI+2:0] SigmaLatch; // Latches output of Sigma adder
reg [`MSBI+2:0] DeltaB; // B input of Delta adder
always @(SigmaLatch) DeltaB = {SigmaLatch[`MSBI+2], SigmaLatch[`MSBI+2]} << (`MSBI+1);
always @(DACin or DeltaB) DeltaAdder = DACin + DeltaB;
always @(DeltaAdder or SigmaLatch) SigmaAdder = DeltaAdder + SigmaLatch;
always @(posedge Clk or posedge Reset)
begin
if (Reset) begin
SigmaLatch <= #1 1'b1 << (`MSBI+1);
DACout <= #1 1'b0;
end else begin
SigmaLatch <= #1 SigmaAdder;
DACout <= #1 SigmaLatch[`MSBI+2];
end
end
endmodule
module top(
input clka,
output [2:0] vga_red,
output [2:0] vga_green,
output [2:0] vga_blue,
output vga_hsync_n,
output vga_vsync_n,
input SCK, // arduino 13
input MOSI, // arduino 11
inout MISO, // arduino 12
input SSEL, // arduino 9
inout AUX, // arduino 2
output AUDIOL,
output AUDIOR,
output flashMOSI,
input flashMISO,
output flashSCK,
output flashSSEL
);
wire mem_clk;
wire [7:0] host_mem_data_wr;
reg [7:0] mem_data_rd;
reg [7:0] latched_mem_data_rd;
wire [14:0] mem_w_addr; // Combined write address
wire [14:0] mem_r_addr; // Combined read address
wire [14:0] host_mem_w_addr;
wire [14:0] host_mem_r_addr;
wire host_mem_wr;
wire mem_rd;
wire vga_clk;
ck_div #(.DIV_BY(2), .MULT_BY(4)) vga_ck_gen(.ck_in(clka), .ck_out(vga_clk));
wire [15:0] j1_insn;
wire [12:0] j1_insn_addr;
wire [15:0] j1_mem_addr;
wire [15:0] j1_mem_dout;
wire j1_mem_wr;
wire [7:0] j1insnl_read;
wire [7:0] j1insnh_read;
wire [7:0] mem_data_rd0;
wire [7:0] mem_data_rd1;
wire [7:0] mem_data_rd2;
wire [7:0] mem_data_rd3;
wire [7:0] mem_data_rd4;
wire [7:0] mem_data_rd5;
wire gdMISO;
always @(posedge vga_clk)
if (mem_rd)
latched_mem_data_rd <= mem_data_rd;
SPI_memory spi1(
.clk(vga_clk),
.SCK(SCK), .MOSI(MOSI), .MISO(gdMISO), .SSEL(SSEL),
.raddr(host_mem_r_addr),
.waddr(host_mem_w_addr),
.data_w(host_mem_data_wr),
.data_r(latched_mem_data_rd),
.we(host_mem_wr),
.re(mem_rd),
.mem_clk(mem_clk));
wire host_busy = host_mem_wr | mem_rd;
wire mem_wr = host_busy ? host_mem_wr : j1_mem_wr;
wire [7:0] mem_data_wr = host_busy ? host_mem_data_wr : j1_mem_dout;
wire [14:0] mem_addr = host_busy ? (host_mem_wr ? host_mem_w_addr : host_mem_r_addr) : j1_mem_addr;
assign mem_w_addr = host_busy ? host_mem_w_addr : j1_mem_addr;
assign mem_r_addr = host_busy ? host_mem_r_addr : j1_mem_addr;
reg signed [15:0] sample_l;
reg signed [15:0] sample_r;
reg [6:0] modvoice = 64;
reg [14:0] bg_color;
reg [7:0] pin2mode = 0;
wire pin2f = (pin2mode == 8'h46);
wire pin2j = (pin2mode == 8'h4A);
wire flashsel = (AUX == 0) & pin2f;
assign MISO = SSEL ? (flashsel ? flashMISO : 1'bz) : gdMISO;
// assign MISO = SSEL ? (1'bz ) : gdMISO;
// PULLUP MISO_pullup(.O(MISO));
// IOBUF MISO_iobuf(
// .I(gdMISO),
// .IO(MISO),
// .T(SSEL));
// user-visible registers
reg [7:0] frames;
reg [8:0] scrollx;
reg [8:0] scrolly;
reg jkmode;
wire [7:0] palette16l_read;
wire [7:0] palette16h_read;
wire [4:0] palette16_addr;
wire [15:0] palette16_data;
// 11'b00001xxxxx0: low
wire palette16_wr = (mem_wr & (mem_w_addr[14:11] == 5) & (mem_w_addr[10:6] == 1));
ram32x8d palette16l(
.a(mem_addr[5:1]),
.wclk(mem_clk),
.wea((mem_w_addr[0] == 0) & palette16_wr),
.ad(mem_data_wr),
.ao(palette16l_read),
.b(palette16_addr),
.bo(palette16_data[7:0]));
ram32x8d palette16h(
.a(mem_addr[5:1]),
.wclk(mem_clk),
.wea((mem_w_addr[0] == 1) & palette16_wr),
.ad(mem_data_wr),
.ao(palette16h_read),
.b(palette16_addr),
.bo(palette16_data[15:8]));
wire [7:0] palette4l_read;
wire [7:0] palette4h_read;
wire [4:0] palette4_addr;
wire [15:0] palette4_data;
// 11'b00010xxxxx0: low
wire palette4_wr = (mem_wr & (mem_w_addr[14:11] == 5) & (mem_w_addr[10:6] == 2));
ram32x8d palette4l(
.a(mem_addr[5:1]),
.wclk(mem_clk),
.wea((mem_w_addr[0] == 0) & palette4_wr),
.ad(mem_data_wr),
.ao(palette4l_read),
.b(palette4_addr),
.bo(palette4_data[7:0]));
ram32x8d palette4h(
.a(mem_addr[5:1]),
.wclk(mem_clk),
.wea((mem_w_addr[0] == 1) & palette4_wr),
.ad(mem_data_wr),
.ao(palette4h_read),
.b(palette4_addr),
.bo(palette4_data[15:8]));
// Generate CounterX and CounterY
// A single line is 1040 clocks. Line pair is 2080 clocks.
reg [10:0] CounterX;
reg [9:0] CounterY;
wire CounterXmaxed = (CounterX==1040);
always @(posedge vga_clk)
if(CounterXmaxed)
CounterX <= 0;
else
CounterX <= CounterX + 1;
wire lastline = (CounterY == 665);
wire [9:0] _CounterY = lastline ? 0 : (CounterY + 1);
always @(posedge vga_clk)
if (CounterXmaxed) begin
CounterY <= _CounterY;
if (lastline)
frames <= frames + 1;
end
reg [12:0] comp_workcnt; // Compositor work address
reg comp_workcnt_lt_400;
always @(posedge vga_clk)
begin
if (CounterXmaxed & (CounterY[0] == 0)) begin
comp_workcnt <= 0;
comp_workcnt_lt_400 <= 1;
end else begin
comp_workcnt <= comp_workcnt + 1;
if (comp_workcnt == 399)
comp_workcnt_lt_400 <= 0;
end
end
// horizontal
// Front porch 56
// Sync 120
// Back porch 64
// vertical
// Front porch 37 lines
// Sync 6
// Back porch 23
// `define HSTART (53 + 120 + 61)
`define HSTART 0
reg vga_HS, vga_VS, vga_active;
always @(posedge vga_clk)
begin
vga_HS <= ((800 + 61) <= CounterX) & (CounterX < (800 + 61 + 120));
vga_VS <= (35 <= CounterY) & (CounterY < (35 + 6));
vga_active = ((`HSTART + 1) <= CounterX) & (CounterX < (`HSTART + 1 + 800)) & ((35 + 6 + 21) < CounterY) & (CounterY <= (35 + 6 + 21 + 600));
end
wire [10:0] xx = (CounterX - `HSTART);
wire [10:0] xx_1 = (CounterX - `HSTART + 1);
wire [10:0] yy = (CounterY + 2 - (35 + 6 + 21 + 1)); // yy range 0-665
wire [10:0] column = comp_workcnt + scrollx;
wire [10:0] row = yy[10:1] + scrolly;
wire [7:0] glyph;
wire [11:0] picaddr = {row[8:3], column[8:3]};
wire en_pic = (mem_addr[14:12] == 0);
RAM_PICTURE picture(
.dia(0),
.doa(glyph),
.wea(0),
.ena(1),
.clka(vga_clk),
.addra(picaddr),
.dib(mem_data_wr),
.dob(mem_data_rd0),
.web(mem_wr),
.enb(en_pic),
.clkb(mem_clk),
.addrb(mem_addr)
);
reg [2:0] _column;
always @(posedge vga_clk)
_column = column;
wire en_chr = (mem_addr[14:12] == 1);
wire [1:0] charout;
RAM_CHR chars(
.dia(0), .doa(charout), .wea(0), .ena(1), .clka(vga_clk), .addra({glyph, row[2:0], _column[2], ~_column[1:0]}),
.dib(mem_data_wr), .dob(mem_data_rd1), .web(mem_wr), .enb(en_chr), .clkb(mem_clk), .addrb(mem_addr));
reg [7:0] _glyph;
always @(posedge vga_clk)
_glyph <= glyph;
wire [4:0] bg_r;
wire [4:0] bg_g;
wire [4:0] bg_b;
wire en_pal = (mem_addr[14:11] == 4'b0100);
wire [15:0] char_matte;
RAM_PAL charpalette(
.DIA(mem_data_wr),
.WEA(mem_wr),
.ENA(en_pal),
.CLKA(mem_clk),
.ADDRA(mem_addr),
.DOA(mem_data_rd2),
.SSRA(0),
.DIB(0),
.WEB(0),
.ENB(1),
.CLKB(vga_clk),
.ADDRB({_glyph, charout}),
.DOB(char_matte),
.SSRB(0)
);
// wire [4:0] bg_mix_r = bg_color[14:10] + char_matte[14:10];
// wire [4:0] bg_mix_g = bg_color[9:5] + char_matte[9:5];
// wire [4:0] bg_mix_b = bg_color[4:0] + char_matte[4:0];
// wire [14:0] char_final = char_matte[15] ? {bg_mix_r, bg_mix_g, bg_mix_b} : char_matte[14:0];
wire [14:0] char_final = char_matte[15] ? bg_color : char_matte[14:0];
reg [7:0] mem_data_rd_reg;
// Collision detection RAM is readable during vblank
// writes coll_d to coll_w_addr during render
wire coll_rd = (yy >= 600); // 1 means reading
wire [7:0] coll_d;
wire [7:0] coll_w_addr;
wire coll_we;
wire [7:0] coll_addr = coll_rd ? mem_r_addr[7:0] : coll_w_addr;
wire [7:0] coll_o;
ram256x8s coll(.o(coll_o), .a(coll_addr), .d(coll_d), .wclk(vga_clk), .we(~coll_rd & coll_we));
wire [7:0] screenshot_rd;
wire [7:0] voicefl_read;
wire [7:0] voicefh_read;
wire [7:0] voicela_read;
wire [7:0] voicera_read;
reg j1_reset = 0;
reg spr_disable = 0;
reg spr_page = 0;
// Screenshot notes
// three states, controlled by screenshot_primed, _done:
// primed done composer.A
// 0 0 screenshot disabled write(comp_write)
// 1 0 screenshot primed write(comp_write)
// 1 1 screenshot done read(mem_r_addr[9:1])
reg [8:0] screenshot_yy; // 9 bits, 0-400
reg screenshot_primed;
reg screenshot_done;
wire screenshot_reset;
wire [8:0] public_yy = coll_rd ? 300 : yy[10:1];
always @(posedge vga_clk)
begin
if (screenshot_reset)
screenshot_done <= 0;
else if (CounterXmaxed & screenshot_primed & !screenshot_done & (public_yy == screenshot_yy)) begin
screenshot_done <= 1;
end
end
always @(mem_data_rd_reg)
begin
casex (mem_r_addr[10:0])
11'h000: mem_data_rd_reg <= 8'h6d; // Gameduino ident
11'h001: mem_data_rd_reg <= `REVISION;
11'h002: mem_data_rd_reg <= frames;
11'h003: mem_data_rd_reg <= coll_rd; // called VBLANK, but really "is coll readable?"
11'h004: mem_data_rd_reg <= scrollx[7:0];
11'h005: mem_data_rd_reg <= scrollx[8];
11'h006: mem_data_rd_reg <= scrolly[7:0];
11'h007: mem_data_rd_reg <= scrolly[8];
11'h008: mem_data_rd_reg <= jkmode;
11'h009: mem_data_rd_reg <= j1_reset;
11'h00a: mem_data_rd_reg <= spr_disable;
11'h00b: mem_data_rd_reg <= spr_page;
11'h00c: mem_data_rd_reg <= pin2mode;
11'h00e: mem_data_rd_reg <= bg_color[7:0];
11'h00f: mem_data_rd_reg <= bg_color[14:8];
11'h010: mem_data_rd_reg <= sample_l[7:0];
11'h011: mem_data_rd_reg <= sample_l[15:8];
11'h012: mem_data_rd_reg <= sample_r[7:0];
11'h013: mem_data_rd_reg <= sample_r[15:8];
11'h014: mem_data_rd_reg <= modvoice;
11'h01e: mem_data_rd_reg <= public_yy[7:0];
11'h01f: mem_data_rd_reg <= {screenshot_done, 6'b000000, public_yy[8]};
11'b00001xxxxx0: mem_data_rd_reg <= palette16l_read;
11'b00001xxxxx1: mem_data_rd_reg <= palette16h_read;
11'b00010xxxxx0: mem_data_rd_reg <= palette4l_read;
11'b00010xxxxx1: mem_data_rd_reg <= palette4h_read;
11'b001xxxxxxxx:
mem_data_rd_reg <= coll_rd ? coll_o : 8'hff;
11'b010xxxxxx00: mem_data_rd_reg <= voicefl_read;
11'b010xxxxxx01: mem_data_rd_reg <= voicefh_read;
11'b010xxxxxx10: mem_data_rd_reg <= voicela_read;
11'b010xxxxxx11: mem_data_rd_reg <= voicera_read;
11'b011xxxxxxx0: mem_data_rd_reg <= j1insnl_read;
11'b011xxxxxxx1: mem_data_rd_reg <= j1insnh_read;
11'b1xxxxxxxxxx: mem_data_rd_reg <= screenshot_rd;
// default: mem_data_rd_reg <= 0;
endcase
end
reg [17:0] soundcounter;
always @(posedge vga_clk)
soundcounter <= soundcounter + 1;
wire [5:0] viN = soundcounter + 1;
wire [5:0] vi = soundcounter;
wire voice_wr = mem_wr & (mem_w_addr[14:11] == 5) & (mem_w_addr[10:8] == 3'b010);
wire voicefl_wr = voice_wr & (mem_w_addr[1:0] == 2'b00);
wire voicefh_wr = voice_wr & (mem_w_addr[1:0] == 2'b01);
wire voicela_wr = voice_wr & (mem_w_addr[1:0] == 2'b10);
wire voicera_wr = voice_wr & (mem_w_addr[1:0] == 2'b11);
wire [7:0] voicela_data;
wire [7:0] voicera_data;
wire [7:0] voicefl_data;
wire [7:0] voicefh_data;
wire [5:0] voice_addr = mem_addr[7:2];
ram64x8d voicefl(
.a(voice_addr),
.wclk(mem_clk),
.wea(voicefl_wr),
.ad(mem_data_wr),
.ao(voicefl_read),
.b(viN),
.bo(voicefl_data));
ram64x8d voicefh(
.a(voice_addr),
.wclk(mem_clk),
.wea(voicefh_wr),
.ad(mem_data_wr),
.ao(voicefh_read),
.b(viN),
.bo(voicefh_data));
ram64x8d voicela(
.a(voice_addr),
.wclk(mem_clk),
.wea(voicela_wr),
.ad(mem_data_wr),
.ao(voicela_read),
.b(viN),
.bo(voicela_data));
ram64x8d voicera(
.a(voice_addr),
.wclk(mem_clk),
.wea(voicera_wr),
.ad(mem_data_wr),
.ao(voicera_read),
.b(viN),
.bo(voicera_data));
assign screenshot_reset = mem_wr & (mem_w_addr[14:11] == 5) & (mem_w_addr[10:0] == 11'h01f);
always @(posedge mem_clk)
begin
if (mem_wr & mem_w_addr[14:11] == 5)
casex (mem_w_addr[10:0])
11'h004: scrollx[7:0] <= mem_data_wr;
11'h005: scrollx[8] <= mem_data_wr;
11'h006: scrolly[7:0] <= mem_data_wr;
11'h007: scrolly[8] <= mem_data_wr;
11'h008: jkmode <= mem_data_wr;
11'h009: j1_reset <= mem_data_wr;
11'h00a: spr_disable <= mem_data_wr;
11'h00b: spr_page <= mem_data_wr;
11'h00c: pin2mode <= mem_data_wr;
11'h00e: bg_color[7:0] <= mem_data_wr;
11'h00f: bg_color[14:8] <= mem_data_wr;
11'h010: sample_l[7:0] <= mem_data_wr;
11'h011: sample_l[15:8] <= mem_data_wr;
11'h012: sample_r[7:0] <= mem_data_wr;
11'h013: sample_r[15:8] <= mem_data_wr;
11'h014: modvoice <= mem_data_wr;
11'h01e: screenshot_yy[7:0] <= mem_data_wr;
11'h01f: begin screenshot_primed <= mem_data_wr[7];
screenshot_yy[8] <= mem_data_wr; end
endcase
end
/*
0000-0fff Picture
1000-1fff Character
2000-27ff Character
2800-2fff (Unused)
3000-37ff Sprite values
3800-3fff Sprite palette
4000-7fff Sprite image
*/
always @*
begin
case (mem_addr[14:11]) // 2K pages
4'h0: mem_data_rd <= mem_data_rd0; // pic
4'h1: mem_data_rd <= mem_data_rd0;
4'h2: mem_data_rd <= mem_data_rd1; // chr
4'h3: mem_data_rd <= mem_data_rd1;
4'h4: mem_data_rd <= mem_data_rd2; // pal
4'h5: mem_data_rd <= mem_data_rd_reg;
4'h6: mem_data_rd <= mem_data_rd3; // sprval
4'h7: mem_data_rd <= mem_data_rd4; // sprpal
4'h8: mem_data_rd <= mem_data_rd5; // sprimg
4'h9: mem_data_rd <= mem_data_rd5; // sprimg
4'ha: mem_data_rd <= mem_data_rd5; // sprimg
4'hb: mem_data_rd <= mem_data_rd5; // sprimg
4'hc: mem_data_rd <= mem_data_rd5; // sprimg
4'hd: mem_data_rd <= mem_data_rd5; // sprimg
4'he: mem_data_rd <= mem_data_rd5; // sprimg
4'hf: mem_data_rd <= mem_data_rd5; // sprimg
default: mem_data_rd <= 8'h97;
endcase
end
// Sprite memory
// Stage 1: scan for valid
reg [8:0] s1_count;
wire en_sprval = (mem_addr[14:11] == 4'b0110);
wire [31:0] sprval_data;
RAM_SPRVAL sprval(
.DIA(mem_data_wr),
.WEA(mem_wr),
.ENA(en_sprval),
.CLKA(mem_clk),
.ADDRA(mem_addr),
.DOA(mem_data_rd3),
.SSRA(0),
.DIB(0),
.WEB(0),
.ENB(1),
.CLKB(vga_clk),
.ADDRB({spr_page, s1_count[7:0]}),
.DOB(sprval_data),
.SSRB(0)
);
wire [9:0] sprpal_addr;
wire [15:0] sprpal_data;
wire en_sprpal = (mem_addr[14:11] == 4'b0111);
RAM_SPRPAL sprpal(
.DIA(mem_data_wr),
.WEA(mem_wr),
.ENA(en_sprpal),
.CLKA(mem_clk),
.ADDRA(mem_addr),
.DOA(mem_data_rd4),
.SSRA(0),
.DIB(0),
.WEB(0),
.ENB(1),
.CLKB(vga_clk),
.ADDRB(sprpal_addr),
.DOB(sprpal_data),
.SSRB(0)
);
wire [13:0] sprimg_readaddr;
wire [7:0] sprimg_data;
wire en_sprimg = (mem_addr[14] == 1'b1);
// ram16K_8_8 sprimg(
RAM_SPRIMG sprimg(
.dia(mem_data_wr),
.wea(mem_wr),
.ena(en_sprimg),
.clka(mem_clk),
.addra(mem_addr),
.doa(mem_data_rd5),
.ssra(0),
.dib(0),
.web(0),
.enb(1),
.clkb(vga_clk),
.addrb(sprimg_readaddr),
.dob(sprimg_data),
.ssrb(0)
);
// Stage 1: scan for valid
reg s1_consider; // Consider the sprval on the next cycle
wire s2_room; // Does s2 fifo have room for one entry?
always @(posedge vga_clk)
begin
if (comp_workcnt == 0) begin
s1_count <= 0;
s1_consider <= 0;
end else
if ((s1_count <= 255) & s2_room) begin
s1_count <= s1_count + 1;
s1_consider <= 1;
end else begin
s1_consider <= 0;
end
end
wire [31:0] s1_out = sprval_data;
wire [8:0] s1_y_offset = yy[9:1] - s1_out[24:16];
wire s1_visible = (spr_disable == 0) & (s1_y_offset[8:4] == 0);
wire s1_valid = s1_consider & s1_visible;
reg [8:0] s1_id;
always @(posedge vga_clk)
s1_id <= s1_count;
// Stage 2: fifo
wire [4:0] s2_fullness;
wire s3_read;
wire [40:0] s2_out;
fifo #(40) s2(.clk(vga_clk),
.wr(s1_valid), .datain({s1_id, s1_out}),
.rd(s3_read), .dataout(s2_out),
.fullness(s2_fullness));
assign s2_room = (s2_fullness < 14);
wire s2_valid = s2_fullness != 0;
// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
// [ image ] [ y ] [PAL] [ ROT ] [ x ]
/* Stage 3: read sprimg
consume s2_out on last cycle
out: s3_valid, s3_pal, s3_out, s3_compaddr
*/
reg [4:0] s3_state;
reg [3:0] s3_pal;
reg [31:0] s3_in;
assign s3_read = (s3_state == 15);
always @(posedge vga_clk)
begin
if (comp_workcnt < 403)
s3_state <= 16;
else if (s3_state == 16) begin
if (s2_valid) begin
s3_state <= 0;
s3_in <= s2_out;
end
end else begin
s3_state <= s3_state + 1;
end
s3_pal <= s2_out[15:12];
end
wire [3:0] s3_yoffset = yy[4:1] - s2_out[19:16];
wire [3:0] s3_prev_state = (s3_state == 16) ? 0 : (s3_state + 1);
wire [3:0] readx = (s2_out[9] ? s3_yoffset : s3_prev_state) ^ {4{s2_out[10]}};
wire [3:0] ready = (s2_out[9] ? s3_prev_state : s3_yoffset) ^ {4{s2_out[11]}};
assign sprimg_readaddr = {s2_out[30:25], ready, readx};
wire [7:0] s3_out = sprimg_data;
wire [8:0] s3_compaddr = s2_out[8:0] + s3_state;
wire s3_valid = (s3_state != 16) & (s3_compaddr < 400);
reg [8:0] s3_id;
reg s3_jk;
always @(posedge vga_clk)
begin
s3_id <= s2_out[40:32];
s3_jk <= s2_out[31];
end
/* Stage 4: read sprpal
out: s4_valid, s4_out, s4_compaddr
*/
reg [15:0] sprpal4;
reg [15:0] sprpal16;
assign sprpal_addr = {s3_pal[1:0], s3_out};
reg [8:0] s4_compaddr;
reg s4_valid;
reg [8:0] s4_id;
reg s4_jk;
wire [3:0] subfield4 = s3_pal[1] ? s3_out[7:4] : s3_out[3:0];
wire [1:0] subfield2 = s3_pal[2] ? (s3_pal[1] ? s3_out[7:6] : s3_out[5:4]) : (s3_pal[1] ? s3_out[3:2] : s3_out[1:0]);
assign palette4_addr = {s3_pal[0], subfield2};
assign palette16_addr = {s3_pal[0], subfield4};
always @(posedge vga_clk)
begin
s4_compaddr <= s3_compaddr;
s4_valid <= s3_valid;
s4_id <= s3_id;
s4_jk <= s3_jk;
sprpal4 <= palette4_data;
sprpal16 <= palette16_data;
end
wire [15:0] s4_out = s3_pal[3] ? sprpal4 : ((s3_pal[3:2] == 0) ? sprpal_data : sprpal16);
// Common signals for collision and composite
wire sprite_write = s4_valid & !s4_out[15]; // transparency
// Collision detect
// Have 400x9 occupancy buffer. If NEW overwrites a fragment OLD
// (and their groups differ) write OLD to coll[NEW].
// Reset coll to FF at start of frame.
// Reset occ to FF at start of line, since sprites drawn 0->ff,
// ff is impossible and means empty.
wire coll_scrub = (yy == 0) & (comp_workcnt < 256);
wire [8:0] occ_addr = comp_workcnt_lt_400 ? comp_workcnt : s4_compaddr;
wire [8:0] occ_d = comp_workcnt_lt_400 ? 9'hff : {s4_jk, s4_id[7:0]};
wire [8:0] oldocc;
wire occ_w = comp_workcnt_lt_400 | sprite_write;
ram400x9s occ(.o(oldocc), .a(occ_addr), .d(occ_d), .wclk(vga_clk), .we(occ_w));
assign coll_d = coll_scrub ? 8'hff : oldocc[7:0];
assign coll_w_addr = coll_scrub ? comp_workcnt : s4_id[7:0];
// old contents 0xff, never write
// jkmode=1 and JK's differ, allow write
wire overwriting = (oldocc[7:0] != 8'hff);
wire jkpass = (jkmode == 0) | (oldocc[8] ^ s4_jk);
assign coll_we = coll_scrub | ((403 <= comp_workcnt) & sprite_write & overwriting & jkpass);
// Composite
wire comp_read = yy[1]; // which block is reading
wire [8:0] comp_scanout = xx[9:1];
wire [8:0] comp_write = (comp_workcnt < 403) ? (comp_workcnt - 3) : s4_compaddr;
wire comp_part1 = (3 <= comp_workcnt) & (comp_workcnt < 403);
`ifdef NELLY
wire [14:0] comp_out0;
wire [14:0] comp_out1;
RAMB16_S18_S18 composer(
.DIPA(0),
.DIA(comp_part1 ? char_final : s4_out),
.WEA(comp_read == 1 & (comp_part1 | sprite_write)),
.ENA(1),
.CLKA(vga_clk),
.ADDRA({1'b0, (comp_read == 0) ? comp_scanout : comp_write[8:0]}),
.DOA(comp_out0),
.SSRA(0),
.DIPB(0),
.DIB(comp_part1 ? char_final : s4_out),
.WEB(comp_read == 0 & (comp_part1 | sprite_write)),
.ENB(1),
.CLKB(vga_clk),
.ADDRB({1'b1, (comp_read == 1) ? comp_scanout : comp_write[8:0]}),
.DOB(comp_out1),
.SSRB(0)
);
wire [14:0] comp_out = comp_read ? comp_out1 : comp_out0;
`else
wire ss = screenshot_primed & screenshot_done; // screenshot readout mode
wire [15:0] screenshot_rdHL;
wire [14:0] comp_out;
// Port A is the write, or read when screenshot is ready
// Port B is scanout
RAMB16_S18_S18
composer(
.DIPA(0),
.DIA(comp_part1 ? char_final : s4_out),
.WEA(!ss & (comp_part1 | sprite_write)),
.ENA(1),
.CLKA(vga_clk),
.ADDRA(ss ? {screenshot_yy[0], mem_r_addr[9:1]} : {comp_read, comp_write[8:0]}),
.DOA(screenshot_rdHL),
.SSRA(0),
.DIPB(0),
.DIB(0),
.WEB(0),
.ENB(1),
.CLKB(vga_clk),
.ADDRB({!comp_read, comp_scanout}),
.DOB(comp_out),
.SSRB(0)
);
assign screenshot_rd = mem_r_addr[0] ? screenshot_rdHL[15:8] : screenshot_rdHL[7:0];
`endif
assign {bg_r,bg_g,bg_b} = comp_out;
// Figure out from above signals when composite completes
// by detecting pipeline idle
wire composite_complete = (comp_workcnt > 403) & (s1_count == 256) & !s1_consider & !s2_valid & (s3_state == 16) & !s4_valid;
// Signal generation
wire [16:0] lfsr;
lfsre lfsr0(
.clk(vga_clk),
.lfsr(lfsr));
wire [1:0] dith;
// 0 2
// 3 1
assign dith = {(xx[0]^yy[0]), yy[0]};
wire [5:0] dith_r = (bg_r + dith);
wire [5:0] dith_g = (bg_g + dith);
wire [5:0] dith_b = (bg_b + dith);
wire [2:0] f_r = {3{dith_r[5]}} | dith_r[4:2];
wire [2:0] f_g = {3{dith_g[5]}} | dith_g[4:2];
wire [2:0] f_b = {3{dith_b[5]}} | dith_b[4:2];
wire [2:0] ccc = { charout[1], charout[0], charout[0] };
assign vga_red = vga_active ? f_r : 0;
assign vga_green = vga_active ? f_g : 0;
assign vga_blue = vga_active ? f_b : 0;
assign vga_hsync_n = ~vga_HS;
assign vga_vsync_n = ~vga_VS;
/*
An 18-bit counter, multiplied by the frequency gives a single bit
pulse that advances the voice's wave counter.
Frequency of 4 means 1Hz, 16385 means 4095.75Hz.
18-bit counter increments every 1/(2**18), or 262144 Hz.
*/
`define MASTERFREQ (1 << 22)
reg [27:0] d;
wire [27:0] dInc = d[27] ? (`MASTERFREQ) : (`MASTERFREQ - 50000000);
wire [27:0] dN = d + dInc;
reg [16:0] soundmaster; // This increments at MASTERFREQ Hz
always @(posedge vga_clk)
begin
d = dN;
// clock B tick whenever d[27] is zero
if (dN[27] == 0) begin
soundmaster <= soundmaster + 1;
end
end
wire [6:0] hsin;
wire [6:0] wavecounter;
wire [6:0] note = wavecounter[6:0];
`ifdef YES
RAM64X1S #(.INIT(64'b0000000000110101100010001111010010010111100010001101011000000000) /* 0 */
) sin0(.O(hsin[0]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]), .D(0), .WCLK(vga_clk), .WE(0));
RAM64X1S #(.INIT(64'b0101010101101100011100010101001111100101010001110001101101010101) /* 1 */
) sin1(.O(hsin[1]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]), .D(0), .WCLK(vga_clk), .WE(0));
RAM64X1S #(.INIT(64'b0110011001001001010101001100111111111001100101010100100100110011) /* 2 */
) sin2(.O(hsin[2]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]), .D(0), .WCLK(vga_clk), .WE(0));
RAM64X1S #(.INIT(64'b0010110100100100110011000011111111111110000110011001001001011010) /* 3 */
) sin3(.O(hsin[3]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]), .D(0), .WCLK(vga_clk), .WE(0));
RAM64X1S #(.INIT(64'b0001110011100011110000111111111111111111111000011110001110011100) /* 4 */
) sin4(.O(hsin[4]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]), .D(0), .WCLK(vga_clk), .WE(0));
RAM64X1S #(.INIT(64'b0000001111100000001111111111111111111111111111100000001111100000) /* 5 */
) sin5(.O(hsin[5]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]), .D(0), .WCLK(vga_clk), .WE(0));
RAM64X1S #(.INIT(64'b0000000000011111111111111111111111111111111111111111110000000000) /* 6 */
) sin6(.O(hsin[6]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]), .D(0), .WCLK(vga_clk), .WE(0));
`else
ROM64X1 #(.INIT(64'b0000000000110101100010001111010010010111100010001101011000000000) /* 0 */) sin0(.O(hsin[0]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]));
ROM64X1 #(.INIT(64'b0101010101101100011100010101001111100101010001110001101101010101) /* 1 */) sin1(.O(hsin[1]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]));
ROM64X1 #(.INIT(64'b0110011001001001010101001100111111111001100101010100100100110011) /* 2 */) sin2(.O(hsin[2]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]));
ROM64X1 #(.INIT(64'b0010110100100100110011000011111111111110000110011001001001011010) /* 3 */) sin3(.O(hsin[3]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]));
ROM64X1 #(.INIT(64'b0001110011100011110000111111111111111111111000011110001110011100) /* 4 */) sin4(.O(hsin[4]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]));
ROM64X1 #(.INIT(64'b0000001111100000001111111111111111111111111111100000001111100000) /* 5 */) sin5(.O(hsin[5]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]));
ROM64X1 #(.INIT(64'b0000000000011111111111111111111111111111111111111111110000000000) /* 6 */) sin6(.O(hsin[6]), .A0(note[0]), .A1(note[1]), .A2(note[2]), .A3(note[3]), .A4(note[4]), .A5(note[5]));
`endif
wire signed [7:0] sin = note[6] ? (8'h00 - hsin) : hsin;
wire voiceshape = voicefh_data[7];
wire [14:0] voicefreq = {voicefh_data[6:0], voicefl_data};
wire [35:0] derived = {1'b0, soundmaster} * voicefreq;
wire highfreq = voicefreq[14];
wire newpulse = highfreq ? derived[18] : derived[17]; // pulse is a square wave frequency 64*f
wire oldpulse;
wire [6:0] nextwavecounter = voiceshape ? lfsr : (wavecounter + (highfreq ? 2 : 1));
wire [6:0] _wavecounter = (newpulse != oldpulse) ? nextwavecounter : wavecounter;
`ifdef NELLY
ram64x8s voicestate(
.a(viN),
.we(1),
.wclk(vga_clk),
.d({_wavecounter, newpulse}),
.o({wavecounter, oldpulse}));
`else
wire [8:0] vsi = {_wavecounter, newpulse};
wire [8:0] vso;
ring64 vs0(.clk(vga_clk), .i(vsi[0]), .o(vso[0]));
ring64 vs1(.clk(vga_clk), .i(vsi[1]), .o(vso[1]));
ring64 vs2(.clk(vga_clk), .i(vsi[2]), .o(vso[2]));
ring64 vs3(.clk(vga_clk), .i(vsi[3]), .o(vso[3]));
ring64 vs4(.clk(vga_clk), .i(vsi[4]), .o(vso[4]));
ring64 vs5(.clk(vga_clk), .i(vsi[5]), .o(vso[5]));
ring64 vs6(.clk(vga_clk), .i(vsi[6]), .o(vso[6]));
ring64 vs7(.clk(vga_clk), .i(vsi[7]), .o(vso[7]));
assign wavecounter = vso[7:1];
assign oldpulse = vso[0];
`endif
wire signed [8:0] lamp = voicela_data;
wire signed [8:0] ramp = voicera_data;
reg signed [35:0] lmodulated;
reg signed [35:0] rmodulated;
always @(posedge vga_clk)
begin
lmodulated = lamp * sin;
rmodulated = ramp * sin;
end
// Have lmodulated and rmodulated
reg signed [15:0] lacc;
reg signed [15:0] racc;
wire signed [15:0] lsum = lacc + lmodulated[15:0];
wire signed [15:0] rsum = racc + rmodulated[15:0];
wire signed [31:0] lprod = lacc * lmodulated;
wire signed [31:0] rprod = racc * rmodulated;
wire zeroacc = (vi == 63);
wire [15:0] _lacc = zeroacc ? sample_l : ((vi == modvoice) ? lprod[30:15] : lsum);
wire [15:0] _racc = zeroacc ? sample_r : ((vi == modvoice) ? rprod[30:15] : rsum);
reg signed [12:0] lvalue;
reg signed [12:0] rvalue;
always @(posedge vga_clk)
begin
if (vi == 63) begin
lvalue <= lsum[15:3] /* + sample_l + 32768 */;
rvalue <= rsum[15:3] /* + sample_r + 32768 */;
end
lacc <= _lacc;
racc <= _racc;
end
wire signed [7:0] dither = soundcounter;
// wire [15:0] dither = {soundcounter[0],
// soundcounter[1],
// soundcounter[2],
// soundcounter[3],
// soundcounter[4],
// soundcounter[5],
// soundcounter[6],
// soundcounter[7],
// soundcounter[8],
// soundcounter[9],
// soundcounter[10],
// soundcounter[11],
// soundcounter[12],
// soundcounter[13],
// soundcounter[14],
// soundcounter[15]
// };
`ifdef NELLY
wire lau_out = lvalue >= dither;
wire rau_out = rvalue >= dither;
assign AUDIOL = lau_out;
assign AUDIOR = rau_out;
`else
wire [12:0] ulvalue = lvalue ^ 4096;
wire [12:0] urvalue = rvalue ^ 4096;
dac ldac(AUDIOL, ulvalue, vga_clk, 0);
dac rdac(AUDIOR, urvalue, vga_clk, 0);
`endif
reg [2:0] busyhh;
always @(posedge vga_clk) busyhh = { busyhh[1:0], host_busy };
// J1 Peripherals
reg [7:0] icap_i; // ICAP in
reg icap_write;
reg icap_ce;
reg icap_clk;
wire [7:0] icap_o; // ICAP out
wire icap_busy;
reg j1_p2_dir = 1; // pin defaults to input
reg j1_p2_o = 1;
ICAP_SPARTAN3A ICAP_SPARTAN3A_inst (
.O(icap_o),
.BUSY(icap_busy),
.I(icap_i),
.WRITE(icap_write),
.CE(icap_ce),
.CLK(icap_clk));
reg dna_read;
reg dna_shift;
reg dna_clk;
wire dna_dout;
DNA_PORT dna(
.DOUT(dna_dout),
.DIN(0),
.READ(dna_read),
.SHIFT(dna_shift),
.CLK(dna_clk));
wire j1_wr;
reg [8:0] YYLINE;
wire [9:0] yyline = (CounterY + 4 - (35 + 6 + 21 + 1));
always @(posedge vga_clk)
begin
// if (xx == 400)
if (composite_complete)
YYLINE = yyline[9:1];
end
reg [15:0] freqhz = 8000;
reg [7:0] freqtick;
reg [26:0] freqd;
wire [26:0] freqdN = freqd + freqhz - (freqd[26] ? 0 : 50000000);
always @(posedge vga_clk)
begin
freqd = freqdN;
if (freqd[26] == 0)
freqtick = freqtick + 1;
end
reg [15:0] local_j1_read;
always @*
begin
case ({j1_mem_addr[4:1], 1'b0})
5'h00: local_j1_read <= YYLINE;
5'h02: local_j1_read <= icap_o;
5'h0c: local_j1_read <= freqtick;
5'h0e: local_j1_read <= AUX;
5'h12: local_j1_read <= lfsr;
5'h14: local_j1_read <= soundcounter;
5'h16: local_j1_read <= flashMISO;
5'h18: local_j1_read <= dna_dout;
// default: local_j1_read <= 16'hffff;
endcase
end
wire [0:7] j1_mem_dout_be = j1_mem_dout;
reg j1_flashMOSI;
reg j1_flashSCK;
reg j1_flashSSEL;
always @(posedge vga_clk)
begin
if (j1_wr & (j1_mem_addr[15] == 1))
case ({j1_mem_addr[4:1], 1'b0})
// 5'h06: icap_i <= j1_mem_dout;
// 5'h08: icap_write <= j1_mem_dout;
// 5'h0a: icap_ce <= j1_mem_dout;
// 5'h0c: icap_clk <= j1_mem_dout;
5'h06: {icap_write,icap_ce,icap_clk,icap_i} <= j1_mem_dout;
5'h08: {dna_read, dna_shift, dna_clk} <= j1_mem_dout;
5'h0a: freqhz <= j1_mem_dout;
5'h0e: j1_p2_o <= j1_mem_dout;
5'h10: j1_p2_dir <= j1_mem_dout;
5'h18: j1_flashMOSI <= j1_mem_dout;
5'h1a: j1_flashSCK <= j1_mem_dout;
5'h1c: j1_flashSSEL <= j1_mem_dout;
endcase
end
assign j1_mem_wr = j1_wr & (j1_mem_addr[15] == 0);
j0 j(.sys_clk_i(vga_clk),
.sys_rst_i(j1_reset),
.insn(j1_insn),
.insn_addr(j1_insn_addr),
.mem_wr(j1_wr),
.mem_addr(j1_mem_addr),
.mem_dout(j1_mem_dout),
.mem_din(j1_mem_addr[15] ? local_j1_read : mem_data_rd),
.pause(host_busy | (busyhh != 0))
);
// 0x2b00: j1 insn RAM
wire jinsn_wr = (mem_wr & (mem_w_addr[14:8] == 6'h2b));
RAM_CODEL jinsnl(.b(j1_insn_addr), .bo(j1_insn[7:0]),
.a(mem_addr[7:1]),
.wclk(vga_clk),
.wea((mem_w_addr[0] == 0) & jinsn_wr),
.ad(mem_data_wr),
.ao(j1insnl_read));
RAM_CODEH jinsnh(.b(j1_insn_addr), .bo(j1_insn[15:8]),
.a(mem_addr[7:1]),
.wclk(vga_clk),
.wea((mem_w_addr[0] == 1) & jinsn_wr),
.ad(mem_data_wr),
.ao(j1insnh_read));
assign flashMOSI = pin2j ? j1_flashMOSI : MOSI;
assign flashSCK = pin2j ? j1_flashSCK : SCK;
assign flashSSEL = pin2f ? AUX : (pin2j ? j1_flashSSEL : 1);
assign AUX = (pin2j & (j1_p2_dir == 0)) ? j1_p2_o : 1'bz;
endmodule // top