First commit

This commit is contained in:
2020-09-19 23:42:44 +02:00
commit 90e280af07
442 changed files with 119061 additions and 0 deletions

158
src/avr_interface.v Normal file
View File

@@ -0,0 +1,158 @@
module avr_interface #(
parameter CLK_RATE = 50000000,
parameter SERIAL_BAUD_RATE = 500000
)(
input clk,
input rst,
// cclk, or configuration clock is used when the FPGA is begin configured.
// The AVR will hold cclk high when it has finished initializing.
// It is important not to drive the lines connecting to the AVR
// until cclk is high for a short period of time to avoid contention.
input cclk,
// AVR SPI Signals
output spi_miso,
input spi_mosi,
input spi_sck,
input spi_ss,
output [3:0] spi_channel,
// AVR Serial Signals
output tx,
input rx,
// ADC Interface Signals
input [3:0] channel,
output new_sample,
output [9:0] sample,
output [3:0] sample_channel,
// Serial TX User Interface
input [7:0] tx_data,
input new_tx_data,
output tx_busy,
input tx_block,
// Serial Rx User Interface
output [7:0] rx_data,
output new_rx_data
);
wire ready;
wire n_rdy = !ready;
wire spi_done;
wire [7:0] spi_dout;
wire tx_m;
wire spi_miso_m;
reg byte_ct_d, byte_ct_q;
reg [9:0] sample_d, sample_q;
reg new_sample_d, new_sample_q;
reg [3:0] sample_channel_d, sample_channel_q;
reg [3:0] block_d, block_q;
reg busy_d, busy_q;
// cclk_detector is used to detect when cclk is high signaling when
// the AVR is ready
cclk_detector #(.CLK_RATE(CLK_RATE)) cclk_detector (
.clk(clk),
.rst(rst),
.cclk(cclk),
.ready(ready)
);
spi_slave spi_slave (
.clk(clk),
.rst(n_rdy),
.ss(spi_ss),
.mosi(spi_mosi),
.miso(spi_miso_m),
.sck(spi_sck),
.done(spi_done),
.din(8'hff),
.dout(spi_dout)
);
// CLK_PER_BIT is the number of cycles each 'bit' lasts for
// rtoi converts a 'real' number to an 'integer'
parameter CLK_PER_BIT = $rtoi($ceil(CLK_RATE/SERIAL_BAUD_RATE));
serial_rx #(.CLK_PER_BIT(CLK_PER_BIT)) serial_rx (
.clk(clk),
.rst(n_rdy),
.rx(rx),
.data(rx_data),
.new_data(new_rx_data)
);
serial_tx #(.CLK_PER_BIT(CLK_PER_BIT)) serial_tx (
.clk(clk),
.rst(n_rdy),
.tx(tx_m),
.block(busy_q),
.busy(tx_busy),
.data(tx_data),
.new_data(new_tx_data)
);
// Output declarations
assign new_sample = new_sample_q;
assign sample = sample_q;
assign sample_channel = sample_channel_q;
// these signals connect to the AVR and should be Z when the AVR isn't ready
assign spi_channel = ready ? channel : 4'bZZZZ;
assign spi_miso = ready && !spi_ss ? spi_miso_m : 1'bZ;
assign tx = ready ? tx_m : 1'bZ;
always @(*) begin
byte_ct_d = byte_ct_q;
sample_d = sample_q;
new_sample_d = 1'b0;
sample_channel_d = sample_channel_q;
busy_d = busy_q;
block_d = {block_q[2:0], tx_block};
if (block_q[3] ^ block_q[2])
busy_d = 1'b0;
if (!tx_busy && new_tx_data)
busy_d = 1'b1;
if (spi_ss) begin // device is not selected
byte_ct_d = 1'b0;
end
if (spi_done) begin // sent/received data from SPI
if (byte_ct_q == 1'b0) begin
sample_d[7:0] = spi_dout; // first byte is the 8 LSB of the sample
byte_ct_d = 1'b1;
end else begin
sample_d[9:8] = spi_dout[1:0]; // second byte is the channel 2 MSB of the sample
sample_channel_d = spi_dout[7:4]; // and the channel that was sampled
byte_ct_d = 1'b1; // slave-select must be brought high before the next transfer
new_sample_d = 1'b1;
end
end
end
always @(posedge clk) begin
if (n_rdy) begin
byte_ct_q <= 1'b0;
sample_q <= 10'b0;
new_sample_q <= 1'b0;
end else begin
byte_ct_q <= byte_ct_d;
sample_q <= sample_d;
new_sample_q <= new_sample_d;
end
block_q <= block_d;
busy_q <= busy_d;
sample_channel_q <= sample_channel_d;
end
endmodule

41
src/cclk_detector.v Normal file
View File

@@ -0,0 +1,41 @@
module cclk_detector #(
parameter CLK_RATE = 50000000
)(
input clk,
input rst,
input cclk,
output ready
);
parameter CTR_SIZE = $clog2(CLK_RATE/50000);
reg [CTR_SIZE-1:0] ctr_d, ctr_q;
reg ready_d, ready_q;
assign ready = ready_q;
// ready should only go high once cclk has been high for a while
// if cclk ever falls, ready should go low again
always @(ctr_q or cclk) begin
ready_d = 1'b0;
if (cclk == 1'b0) begin // when cclk is 0 reset the counter
ctr_d = 1'b0;
end else if (ctr_q != {CTR_SIZE{1'b1}}) begin
ctr_d = ctr_q + 1'b1; // counter isn't max value yet
end else begin
ctr_d = ctr_q;
ready_d = 1'b1; // counter reached the max, we are ready
end
end
always @(posedge clk) begin
if (rst) begin
ctr_q <= 1'b0;
ready_q <= 1'b0;
end else begin
ctr_q <= ctr_d;
ready_q <= ready_d;
end
end
endmodule

44
src/mojo.ucf Normal file
View File

@@ -0,0 +1,44 @@
#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05
NET "clk" TNM_NET = clk;
TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;
# PlanAhead Generated physical constraints
NET "clk" LOC = P56 | IOSTANDARD = LVTTL;
NET "rst_n" LOC = P38 | IOSTANDARD = LVTTL;
NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;
NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;
NET "hdmi1_tmds(3)" LOC = "P144" |IOSTANDARD = TMDS_33 | CLOCK_DEDICATED_ROUTE = FALSE ; # Clock
NET "hdmi1_tmdsb(3)" LOC = "P143" |IOSTANDARD = TMDS_33 | CLOCK_DEDICATED_ROUTE = FALSE ;
NET "hdmi1_tmds(2)" LOC = "P138" |IOSTANDARD = TMDS_33 ; # Red
NET "hdmi1_tmdsb(2)" LOC = "P137" |IOSTANDARD = TMDS_33 ;
NET "hdmi1_tmds(1)" LOC = "P140" |IOSTANDARD = TMDS_33 ; # Green
NET "hdmi1_tmdsb(1)" LOC = "P139" |IOSTANDARD = TMDS_33 ;
NET "hdmi1_tmds(0)" LOC = "P142" |IOSTANDARD = TMDS_33 ; # Blue
NET "hdmi1_tmdsb(0)" LOC = "P141" |IOSTANDARD = TMDS_33 ;
NET "zclk" LOC = P23 | IOSTANDARD = LVTTL;
NET "zioreq" LOC = P24 | IOSTANDARD = LVTTL;
NET "zwr" LOC = P21 | IOSTANDARD = LVTTL;
NET "zm1" LOC = P22 | IOSTANDARD = LVTTL;
NET "zrd" LOC = P15 | IOSTANDARD = LVTTL;
NET "zdata(1)" LOC = P114 | IOSTANDARD = LVTTL;
NET "zdata(0)" LOC = P115 | IOSTANDARD = LVTTL;
NET "zdata(2)" LOC = P116 | IOSTANDARD = LVTTL;
NET "zdata(3)" LOC = P117 | IOSTANDARD = LVTTL;
NET "zdata(4)" LOC = P118 | IOSTANDARD = LVTTL;
NET "zdata(5)" LOC = P119 | IOSTANDARD = LVTTL;
NET "zdata(6)" LOC = P120 | IOSTANDARD = LVTTL;
NET "zdata(7)" LOC = P121 | IOSTANDARD = LVTTL;
NET "zaddr(0)" LOC = P104 | IOSTANDARD = LVTTL;
NET "zaddr(1)" LOC = P101 | IOSTANDARD = LVTTL;
NET "zaddr(2)" LOC = P99 | IOSTANDARD = LVTTL;
NET "zaddr(3)" LOC = P97 | IOSTANDARD = LVTTL;

143
src/mojo_top.v Normal file
View File

@@ -0,0 +1,143 @@
module mojo_top(
// 50MHz clock input
input clk,
// Input from reset button (active low)
input rst_n,
// Outputs to the 8 onboard LEDs
output[7:0]led,
output[3:0] hdmi1_tmds,
output[3:0] hdmi1_tmdsb,
input zclk,
input zioreq,
input zwr,
input zm1,
input zrd,
input[7:0] zdata,
input[3:0] zaddr
);
wire rst = ~rst_n; // make reset active high
reg [7:0] red, green, blue;
wire [11:0] x;
wire [10:0] y;
wire [5:0] scroll;
reg[3:0] charx;
reg[3:0] chary;
wire hclk;
wire mclk;
wire [15:0] xy;
wire [7:0] screen_x;
wire [7:0] screen_y;
reg [12:0] waddr;
wire [15:0] write_data;
wire write_enable;
reg [12:0] raddr;
wire [15:0] read_data;
wire [255:0] char;
reg [1:0] control_in;
// 0 Correct address
// 1 Write
wire[23:0] foreground;
wire[23:0] background;
assign led[5:0] = scroll[5:0];
assign led[7:6] = 0;
assign screen_x[7:0] = xy[7:0];
assign screen_y[7:0] = xy[15:8];
hdmi_clk hdmi_clk(.CLK_IN1(clk), .CLK_OUT1(hclk), .CLK_OUT2(mclk));
localparam HEIGHT = 720;
localparam WIDTH = 1280;
hdmi_encoder #(.Y_RES(HEIGHT), .X_RES(WIDTH), .Y_FRAME(HEIGHT+2*16), .X_FRAME(WIDTH+24*16)) hdmi(
.clk(hclk),
.rst(rst),
.tmds(hdmi1_tmds),
.tmdsb(hdmi1_tmdsb),
.x(x),
.y(y),
.red(red),
.green(green),
.blue(blue)
);
microblaze_mcs mcs_0 (
.Clk(mclk), // input Clk
.Reset(rst), // input Reset
.GPO1(write_data), // output [15 : 0] GPO1
.GPO2(xy), // output [15 : 0] GPO2
.GPO3(write_enable), // output [0 : 0] GPO3
.GPO4(scroll), // output [5 : 0] GPO4
.GPI1(zdata), // input [7 : 0] GPI1
.GPI1_Interrupt(), // output GPI1_Interrupt
.GPI2(zclk), // input [0 : 0] GPI2
.GPI2_Interrupt(), // output GPI2_Interrupt
.GPI3(control_in), // input [1 : 0] GPI3
.GPI3_Interrupt(), // output GPI3_Interrupt
.INTC_IRQ() // output INTC_IRQ
);
simple_dual_ram #(.SIZE(16), .DEPTH((80+24)*(45+2))) sram (
.wclk(mclk),
.waddr(waddr),
.write_data(write_data),
.write_en(write_enable),
.rclk(hclk),
.raddr(raddr),
.read_data(read_data)
);
char_map char_map (
.clk(hclk),
.index(read_data[7:0]),
.char(char)
);
color_map foreground_map (
.clk(hclk),
.colorcode(read_data[11:8]),
.color(foreground)
);
color_map backgroundground_map (
.clk(hclk),
.colorcode(read_data[15:12]),
.color(background)
);
always @(*) begin
charx = (x >> 0) % 16;
chary = (y >> 0) % 16;
waddr = (screen_x % (80+24)) + (80+24)*((screen_y + scroll) % (45+2));
raddr = (((x+2) >> 4) % (80+24)) + (80+24)*((( (x > WIDTH) ? ((y+1) >> 4) : (y >> 4) ) + scroll) % (45+2));
if (zaddr == 4'h02) begin
control_in[0] = 1;
end else begin
control_in[0] = 0;
end
if (zioreq == 0 && zm1 == 1 && zwr == 0) begin
control_in[1] = 1;
end else begin
control_in[1] = 0;
end
// @todo Instead of doing + 17 we safe space in the char rom
if (char[255 - charx - 16*chary] == 1) begin
red = foreground[23:16];
green = foreground[15:8];
blue = foreground[7:0];
end else begin
red = background[23:16];
green = background[15:8];
blue = background[7:0];
end
end
endmodule

94
src/serial_rx.v Normal file
View File

@@ -0,0 +1,94 @@
module serial_rx #(
parameter CLK_PER_BIT = 50
)(
input clk,
input rst,
input rx,
output [7:0] data,
output new_data
);
// clog2 is 'ceiling of log base 2' which gives you the number of bits needed to store a value
parameter CTR_SIZE = $clog2(CLK_PER_BIT);
localparam STATE_SIZE = 2;
localparam IDLE = 2'd0,
WAIT_HALF = 2'd1,
WAIT_FULL = 2'd2,
WAIT_HIGH = 2'd3;
reg [CTR_SIZE-1:0] ctr_d, ctr_q;
reg [2:0] bit_ctr_d, bit_ctr_q;
reg [7:0] data_d, data_q;
reg new_data_d, new_data_q;
reg [STATE_SIZE-1:0] state_d, state_q = IDLE;
reg rx_d, rx_q;
assign new_data = new_data_q;
assign data = data_q;
always @(*) begin
rx_d = rx;
state_d = state_q;
ctr_d = ctr_q;
bit_ctr_d = bit_ctr_q;
data_d = data_q;
new_data_d = 1'b0;
case (state_q)
IDLE: begin
bit_ctr_d = 3'b0;
ctr_d = 1'b0;
if (rx_q == 1'b0) begin
state_d = WAIT_HALF;
end
end
WAIT_HALF: begin
ctr_d = ctr_q + 1'b1;
if (ctr_q == (CLK_PER_BIT >> 1)) begin
ctr_d = 1'b0;
state_d = WAIT_FULL;
end
end
WAIT_FULL: begin
ctr_d = ctr_q + 1'b1;
if (ctr_q == CLK_PER_BIT - 1) begin
data_d = {rx_q, data_q[7:1]};
bit_ctr_d = bit_ctr_q + 1'b1;
ctr_d = 1'b0;
if (bit_ctr_q == 3'd7) begin
state_d = WAIT_HIGH;
new_data_d = 1'b1;
end
end
end
WAIT_HIGH: begin
if (rx_q == 1'b1) begin
state_d = IDLE;
end
end
default: begin
state_d = IDLE;
end
endcase
end
always @(posedge clk) begin
if (rst) begin
ctr_q <= 1'b0;
bit_ctr_q <= 3'b0;
new_data_q <= 1'b0;
state_q <= IDLE;
end else begin
ctr_q <= ctr_d;
bit_ctr_q <= bit_ctr_d;
new_data_q <= new_data_d;
state_q <= state_d;
end
rx_q <= rx_d;
data_q <= data_d;
end
endmodule

109
src/serial_tx.v Normal file
View File

@@ -0,0 +1,109 @@
module serial_tx #(
parameter CLK_PER_BIT = 50
)(
input clk,
input rst,
output tx,
input block,
output busy,
input [7:0] data,
input new_data
);
// clog2 is 'ceiling of log base 2' which gives you the number of bits needed to store a value
parameter CTR_SIZE = $clog2(CLK_PER_BIT);
localparam STATE_SIZE = 2;
localparam IDLE = 2'd0,
START_BIT = 2'd1,
DATA = 2'd2,
STOP_BIT = 2'd3;
reg [CTR_SIZE-1:0] ctr_d, ctr_q;
reg [2:0] bit_ctr_d, bit_ctr_q;
reg [7:0] data_d, data_q;
reg [STATE_SIZE-1:0] state_d, state_q = IDLE;
reg tx_d, tx_q;
reg busy_d, busy_q;
reg block_d, block_q;
assign tx = tx_q;
assign busy = busy_q;
always @(*) begin
block_d = block;
ctr_d = ctr_q;
bit_ctr_d = bit_ctr_q;
data_d = data_q;
state_d = state_q;
busy_d = busy_q;
case (state_q)
IDLE: begin
if (block_q) begin
busy_d = 1'b1;
tx_d = 1'b1;
end else begin
busy_d = 1'b0;
tx_d = 1'b1;
bit_ctr_d = 3'b0;
ctr_d = 1'b0;
if (new_data) begin
data_d = data;
state_d = START_BIT;
busy_d = 1'b1;
end
end
end
START_BIT: begin
busy_d = 1'b1;
ctr_d = ctr_q + 1'b1;
tx_d = 1'b0;
if (ctr_q == CLK_PER_BIT - 1) begin
ctr_d = 1'b0;
state_d = DATA;
end
end
DATA: begin
busy_d = 1'b1;
tx_d = data_q[bit_ctr_q];
ctr_d = ctr_q + 1'b1;
if (ctr_q == CLK_PER_BIT - 1) begin
ctr_d = 1'b0;
bit_ctr_d = bit_ctr_q + 1'b1;
if (bit_ctr_q == 7) begin
state_d = STOP_BIT;
end
end
end
STOP_BIT: begin
busy_d = 1'b1;
tx_d = 1'b1;
ctr_d = ctr_q + 1'b1;
if (ctr_q == CLK_PER_BIT - 1) begin
state_d = IDLE;
end
end
default: begin
state_d = IDLE;
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_q <= IDLE;
tx_q <= 1'b1;
end else begin
state_q <= state_d;
tx_q <= tx_d;
end
block_q <= block_d;
data_q <= data_d;
bit_ctr_q <= bit_ctr_d;
ctr_q <= ctr_d;
busy_q <= busy_d;
end
endmodule

79
src/spi_slave.v Normal file
View File

@@ -0,0 +1,79 @@
module spi_slave(
input clk,
input rst,
input ss,
input mosi,
output miso,
input sck,
output done,
input [7:0] din,
output [7:0] dout
);
reg mosi_d, mosi_q;
reg ss_d, ss_q;
reg sck_d, sck_q;
reg sck_old_d, sck_old_q;
reg [7:0] data_d, data_q;
reg done_d, done_q;
reg [2:0] bit_ct_d, bit_ct_q;
reg [7:0] dout_d, dout_q;
reg miso_d, miso_q;
assign miso = miso_q;
assign done = done_q;
assign dout = dout_q;
always @(*) begin
ss_d = ss;
mosi_d = mosi;
miso_d = miso_q;
sck_d = sck;
sck_old_d = sck_q;
data_d = data_q;
done_d = 1'b0;
bit_ct_d = bit_ct_q;
dout_d = dout_q;
if (ss_q) begin
bit_ct_d = 3'b0;
data_d = din;
miso_d = data_q[7];
end else begin
if (!sck_old_q && sck_q) begin // rising edge
data_d = {data_q[6:0], mosi_q};
bit_ct_d = bit_ct_q + 1'b1;
if (bit_ct_q == 3'b111) begin
dout_d = {data_q[6:0], mosi_q};
done_d = 1'b1;
data_d = din;
end
end else if (sck_old_q && !sck_q) begin // falling edge
miso_d = data_q[7];
end
end
end
always @(posedge clk) begin
if (rst) begin
done_q <= 1'b0;
bit_ct_q <= 3'b0;
dout_q <= 8'b0;
miso_q <= 1'b1;
end else begin
done_q <= done_d;
bit_ct_q <= bit_ct_d;
dout_q <= dout_d;
miso_q <= miso_d;
end
sck_q <= sck_d;
mosi_q <= mosi_d;
ss_q <= ss_d;
data_q <= data_d;
sck_old_q <= sck_old_d;
end
endmodule