First commit
This commit is contained in:
158
src/avr_interface.v
Normal file
158
src/avr_interface.v
Normal 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
41
src/cclk_detector.v
Normal 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
44
src/mojo.ucf
Normal 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
143
src/mojo_top.v
Normal 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
94
src/serial_rx.v
Normal 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
109
src/serial_tx.v
Normal 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
79
src/spi_slave.v
Normal 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
|
||||
Reference in New Issue
Block a user