Start over

This commit is contained in:
Andrew Kay
2020-06-14 10:05:02 -05:00
parent ad3979044b
commit 03af715ec5
12 changed files with 2 additions and 775 deletions

View File

@@ -5,7 +5,7 @@ TINYPROG ?= tinyprog
all: top.bin
top.json: top.v hello_world.v coax_tx_bit_timer.v coax_tx.v coax_rx_bit_timer.v coax_rx.v
top.json: top.v
prog: top.bin
$(TINYPROG) -p top.bin

View File

@@ -1,151 +0,0 @@
`default_nettype none
module coax_rx (
input clk,
input rx,
input enable,
input data_read,
output active,
output reg [9:0] data = 10'b0,
output reg data_available = 0
);
parameter CLOCKS_PER_BIT = 8;
reg rx_0 = 0;
reg rx_1 = 0;
localparam IDLE = 0;
localparam LINE_QUIESCE_1 = 1;
localparam LINE_QUIESCE_2 = 2;
localparam LINE_QUIESCE_3 = 3;
localparam LINE_QUIESCE_4 = 4;
localparam LINE_QUIESCE_5 = 5;
localparam LINE_QUIESCE_6 = 6;
localparam CODE_VIOLATION_1A = 7;
localparam CODE_VIOLATION_1B = 8;
localparam CODE_VIOLATION_2 = 9;
localparam CODE_VIOLATION_3A = 10;
localparam CODE_VIOLATION_3B = 11;
localparam SYNC_BIT = 12;
localparam DATA = 13;
localparam PARITY_BIT = 14;
localparam END_1 = 15;
reg [4:0] state = IDLE;
reg [4:0] next_state;
reg [4:0] previous_state = IDLE;
wire bit_timer_enable;
wire bit_timer_sample;
assign bit_timer_enable = (enable && state != CODE_VIOLATION_1A && state != CODE_VIOLATION_3B);
coax_rx_bit_timer #(
.CLOCKS_PER_BIT(CLOCKS_PER_BIT)
) bit_timer (
.clk(clk),
.rx(rx_1),
.enable(bit_timer_enable),
.sample(bit_timer_sample)
);
reg [9:0] input_data = 10'b0;
reg [4:0] input_data_counter;
reg parity_bit;
always @(*)
begin
next_state <= state;
if (state == IDLE)
begin
if (rx_1)
next_state <= LINE_QUIESCE_1;
end
else if (state == CODE_VIOLATION_1A)
begin
if (~rx_1)
next_state <= CODE_VIOLATION_1B;
end
else if (state == CODE_VIOLATION_1B)
begin
if (~rx_1)
next_state <= CODE_VIOLATION_2;
end
else if (state == CODE_VIOLATION_3A)
begin
if (rx_1)
next_state <= CODE_VIOLATION_3B;
end
else if (state == CODE_VIOLATION_3B)
begin
if (~rx_1)
next_state <= SYNC_BIT;
end
else if (bit_timer_sample)
begin
case (state)
LINE_QUIESCE_1: next_state <= rx_1 ? LINE_QUIESCE_2 : IDLE;
LINE_QUIESCE_2: next_state <= rx_1 ? LINE_QUIESCE_3 : IDLE;
LINE_QUIESCE_3: next_state <= rx_1 ? LINE_QUIESCE_4 : IDLE;
LINE_QUIESCE_4: next_state <= rx_1 ? LINE_QUIESCE_5 : IDLE;
LINE_QUIESCE_5: next_state <= rx_1 ? LINE_QUIESCE_6 : IDLE;
LINE_QUIESCE_6: next_state <= rx_1 ? CODE_VIOLATION_1A : IDLE;
CODE_VIOLATION_2: next_state <= rx_1 ? CODE_VIOLATION_3A: IDLE;
SYNC_BIT: next_state <= rx_1 ? DATA : /* TODO: ERROR */ IDLE;
DATA: next_state <= input_data_counter == 9 ? PARITY_BIT : DATA;
PARITY_BIT: next_state <= rx_1 == parity_bit ? END_1 : /* TODO: ERROR... also check for overflow of data */ IDLE;
END_1: next_state <= rx_1 ? DATA : IDLE; // TODO: END_2
endcase
end
end
always @(posedge clk)
begin
rx_0 <= rx;
rx_1 <= rx_0;
if (enable)
begin
if (data_read && data_available)
data_available <= 0;
if (state == DATA)
begin
if (state != previous_state)
begin
input_data <= 10'b0;
input_data_counter <= 0;
parity_bit <= 1; // Even parity includes sync bit
end
else if (bit_timer_sample)
begin
input_data <= { input_data[8:0], rx_1 };
input_data_counter <= input_data_counter + 1;
if (rx_1)
parity_bit <= ~parity_bit;
end
end
else if (state == END_1 && state != previous_state)
begin
data <= input_data;
data_available <= 1;
end
state <= next_state;
previous_state <= state;
end
else
begin
state <= IDLE;
previous_state <= IDLE;
data <= 10'b0;
data_available <= 0;
end
end
assign active = (state >= SYNC_BIT && state <= END_1);
endmodule

View File

@@ -1,38 +0,0 @@
`default_nettype none
module coax_rx_bit_timer (
input clk,
input rx,
input enable,
output sample
);
parameter CLOCKS_PER_BIT = 8;
reg previous_rx;
reg [$clog2(CLOCKS_PER_BIT/2):0] counter = 0;
always @(posedge clk)
begin
if (enable)
begin
if (counter == 0)
begin
if (rx != previous_rx)
counter <= 1;
end
else
begin
counter <= counter + 1;
end
end
else
begin
counter <= 0;
end
previous_rx <= rx;
end
assign sample = (enable && counter == CLOCKS_PER_BIT / 4);
endmodule

View File

@@ -1,188 +0,0 @@
`default_nettype none
module coax_tx (
input clk,
input load,
input [9:0] data,
output full,
output active,
output reg tx, // ??? why does thie have to be reg?
output tx_delay,
output tx_inverted
);
parameter CLOCKS_PER_BIT = 8;
localparam IDLE = 0;
localparam LINE_QUIESCE_1 = 1;
localparam LINE_QUIESCE_2 = 2;
localparam LINE_QUIESCE_3 = 3;
localparam LINE_QUIESCE_4 = 4;
localparam LINE_QUIESCE_5 = 5;
localparam LINE_QUIESCE_6 = 6;
localparam CODE_VIOLATION_1 = 7;
localparam CODE_VIOLATION_2 = 8;
localparam CODE_VIOLATION_3 = 9;
localparam SYNC_BIT = 10;
localparam DATA = 11;
localparam PARITY_BIT = 12;
localparam END_1 = 13;
localparam END_2 = 14;
localparam END_3 = 15;
reg [4:0] state = IDLE;
reg [4:0] next_state;
reg [4:0] previous_state = IDLE;
reg previous_load = 0;
reg [1:0] data_valid = 2'b00;
reg [9:0] holding_data;
reg [9:0] output_data;
reg [3:0] output_data_counter;
reg parity_bit;
reg bit_timer_reset = 0;
wire bit_first_half;
wire bit_second_half;
wire bit_end_strobe;
coax_tx_bit_timer #(
.CLOCKS_PER_BIT(CLOCKS_PER_BIT)
) bit_timer (
.clk(clk),
.reset(bit_timer_reset),
.first_half(bit_first_half),
.second_half(bit_second_half),
.end_strobe(bit_end_strobe)
);
localparam TX_DELAY_CLOCKS = CLOCKS_PER_BIT / 4;
reg [TX_DELAY_CLOCKS-1:0] tx_delay_buffer;
always @(*)
begin
next_state <= state;
if (bit_end_strobe)
begin
case (state)
LINE_QUIESCE_1: next_state <= LINE_QUIESCE_2;
LINE_QUIESCE_2: next_state <= LINE_QUIESCE_3;
LINE_QUIESCE_3: next_state <= LINE_QUIESCE_4;
LINE_QUIESCE_4: next_state <= LINE_QUIESCE_5;
LINE_QUIESCE_5: next_state <= LINE_QUIESCE_6;
LINE_QUIESCE_6: next_state <= CODE_VIOLATION_1;
CODE_VIOLATION_1: next_state <= CODE_VIOLATION_2;
CODE_VIOLATION_2: next_state <= CODE_VIOLATION_3;
CODE_VIOLATION_3: next_state <= SYNC_BIT;
SYNC_BIT: next_state <= DATA;
DATA: next_state <= output_data_counter == 9 ? PARITY_BIT : DATA;
PARITY_BIT: next_state <= data_valid[1] ? SYNC_BIT : END_1;
END_1: next_state <= END_2;
END_2: next_state <= END_3;
END_3: next_state <= IDLE;
endcase
end
end
always @(posedge clk)
begin
previous_state <= state;
state <= next_state;
bit_timer_reset <= 0;
if (load && !previous_load)
begin
if (full)
begin
// TODO: error...
end
else if (data_valid[0])
begin
data_valid <= { 1'b1, data_valid[0] };
holding_data <= data;
end
else
begin
data_valid <= { data_valid[1], 1'b1 };
output_data <= data;
end
if (state == IDLE)
begin
bit_timer_reset <= 1;
// Let's go!
state <= LINE_QUIESCE_1;
end
end
previous_load <= load;
if (state == SYNC_BIT && state != previous_state)
begin
if (!data_valid[0])
begin
data_valid <= { 1'b0, data_valid[1] };
output_data <= holding_data;
end
output_data_counter <= 0;
parity_bit <= 1; // Even parity includes sync bit
end
else if (state == DATA && bit_end_strobe)
begin
output_data <= { output_data[8:0], 1'b0 };
output_data_counter <= output_data_counter + 1;
if (output_data[9])
parity_bit <= ~parity_bit;
end
else if (state == PARITY_BIT && state != previous_state)
begin
data_valid <= { data_valid[1], 1'b0 };
end
end
assign full = data_valid[1]; // TODO: full should be indicated to give setup time at bit 10
assign active = ((state == LINE_QUIESCE_1 && bit_second_half) || state > LINE_QUIESCE_1);
always @(*) // ??? is this best?
begin
tx <= 0;
if (state >= LINE_QUIESCE_1 && state <= LINE_QUIESCE_6)
tx <= bit_first_half ? 0 : 1;
else if (state == CODE_VIOLATION_1)
tx <= 0;
else if (state == CODE_VIOLATION_2)
tx <= bit_first_half ? 0 : 1;
else if (state == CODE_VIOLATION_3)
tx <= 1;
else if (state == SYNC_BIT)
tx <= bit_first_half ? 0 : 1;
else if (state == DATA)
tx <= bit_first_half ? ~output_data[9] : output_data[9];
else if (state == PARITY_BIT)
tx <= bit_first_half ? ~parity_bit : parity_bit;
else if (state == END_1)
tx <= bit_first_half ? 1 : 0;
else if (state == END_2 || state == END_3)
tx <= 1;
end
always @(posedge clk)
begin
// The delayed output is "stretched" to go high when active.
if (!active)
tx_delay_buffer <= { TX_DELAY_CLOCKS{1'b1} };
else
tx_delay_buffer <= { tx_delay_buffer[TX_DELAY_CLOCKS-2:0], tx };
end
assign tx_delay = active ? tx_delay_buffer[TX_DELAY_CLOCKS-1] : 0;
assign tx_inverted = active ? ~tx : 0;
endmodule

View File

@@ -1,33 +0,0 @@
`default_nettype none
module coax_tx_bit_timer (
input clk,
input reset,
output first_half,
output second_half,
output end_strobe
);
parameter CLOCKS_PER_BIT = 8;
reg [$clog2(CLOCKS_PER_BIT):0] counter = 0;
always @(posedge clk or posedge reset)
begin
if (reset)
begin
counter <= 0;
end
else
begin
if (counter == CLOCKS_PER_BIT - 1)
counter <= 0;
else
counter <= counter + 1;
end
end
assign first_half = (counter < CLOCKS_PER_BIT / 2);
assign second_half = ~first_half;
assign end_strobe = (counter == CLOCKS_PER_BIT - 1);
endmodule

View File

@@ -1,110 +0,0 @@
`default_nettype none
module hello_world (
input clk,
output tx_active,
output tx,
output tx_delay,
output tx_inverted
);
wire load;
reg [9:0] data;
wire full;
coax_tx coax_tx (
.clk(clk),
.load(load),
.data(data),
.full(full),
.active(tx_active),
.tx(tx),
.tx_delay(tx_delay),
.tx_inverted(tx_inverted)
);
localparam IDLE = 0;
localparam WORD_1 = 1;
localparam WORD_2 = 2;
localparam WORD_3 = 3;
localparam WORD_4 = 4;
localparam WORD_5 = 5;
localparam WORD_6 = 6;
localparam WORD_7 = 7;
localparam WORD_8 = 8;
localparam WORD_9 = 9;
localparam WORD_10 = 10;
localparam WORD_11 = 11;
localparam WORD_12 = 12;
reg [4:0] state = IDLE;
reg [4:0] next_state;
reg [4:0] previous_state;
always @(*)
begin
next_state <= state;
case (state)
WORD_1: next_state <= WORD_2;
WORD_2: next_state <= WORD_3;
WORD_3: next_state <= WORD_4;
WORD_4: next_state <= WORD_5;
WORD_5: next_state <= WORD_6;
WORD_6: next_state <= WORD_7;
WORD_7: next_state <= WORD_8;
WORD_8: next_state <= WORD_9;
WORD_9: next_state <= WORD_10;
WORD_10: next_state <= WORD_11;
WORD_11: next_state <= WORD_12;
WORD_12: next_state <= IDLE;
endcase
end
reg [23:0] counter = 0;
reg [8:0] state_counter = 0;
always @(posedge clk)
begin
previous_state <= state;
if (counter == 50)
begin
state <= WORD_1;
state_counter <= 0;
end
else if (state > IDLE)
begin
if (state_counter > 32 && !full)
begin
state <= next_state;
state_counter <= 0;
end
else
state_counter <= state_counter + 1;
end
counter <= counter + 1;
end
always @(*)
begin
data <= 10'b0000000000;
case (state)
WORD_1: data <= 10'b0000110001; // WRITE_DATA
WORD_2: data <= 10'b1010011100; // H
WORD_3: data <= 10'b1000010010; // e
WORD_4: data <= 10'b1000101110; // l
WORD_5: data <= 10'b1000101110; // l
WORD_6: data <= 10'b1000111010; // o
WORD_7: data <= 10'b0000000010; // <space>
WORD_8: data <= 10'b1001011010; // w
WORD_9: data <= 10'b1000111010; // o
WORD_10: data <= 10'b1001000100; // r
WORD_11: data <= 10'b1000101110; // l
WORD_12: data <= 10'b1000001100; // d
endcase
end
assign load = state != IDLE && state_counter < 8;
endmodule

View File

@@ -3,25 +3,6 @@
module top (
input clk_16mhz,
// Transmitter
input tx_load,
output tx_full,
output tx_active,
output tx_delay,
output tx_inverted,
// Receiver
input rx_enable,
input rx,
output rx_active,
output rx_data_available,
input rx_data_read,
// Shared data bus
inout [9:0] data,
output debug,
output usb_pu
);
// 19 MHz
@@ -42,39 +23,5 @@ module top (
.PLLOUTCORE(clk_19mhz)
);
wire [9:0] tx_data;
assign tx_data = data;
coax_tx #(
.CLOCKS_PER_BIT(8)
) coax_tx (
.clk(clk_19mhz),
.load(tx_load),
.data(tx_data),
.full(tx_full),
.active(tx_active),
.tx_delay(tx_delay),
.tx_inverted(tx_inverted)
);
wire [9:0] rx_data;
coax_rx #(
.CLOCKS_PER_BIT(8)
) coax_rx (
.clk(clk_19mhz),
.rx(rx),
.enable(rx_enable && !tx_active),
.active(rx_active),
.data(rx_data),
.data_available(rx_data_available),
.data_read(rx_data_read)
);
assign data = rx_enable ? rx_data : 10'bzzzzzzzzzz;
assign debug = rx;
assign usb_pu = 0;
endmodule

View File

@@ -3,12 +3,7 @@ VVP ?= vvp
RTL = ../rtl
all: coax_tx_bit_timer_tb.vcd coax_tx_tb.vcd coax_rx_tb.vcd hello_world_tb.vcd
coax_tx_bit_timer_tb: coax_tx_bit_timer_tb.v $(RTL)/coax_tx_bit_timer.v
coax_tx_tb: coax_tx_tb.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_tx.v
coax_rx_tb: coax_rx_tb.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_tx.v $(RTL)/coax_rx_bit_timer.v $(RTL)/coax_rx.v
hello_world_tb: hello_world_tb.v $(RTL)/hello_world.v $(RTL)/coax_tx_bit_timer.v $(RTL)/coax_tx.v
all:
clean:
rm -f *_tb *.vcd

View File

@@ -1,70 +0,0 @@
`default_nettype none
module coax_rx_tb();
reg clk = 0;
initial
begin
forever
begin
#1 clk <= ~clk;
end
end
reg tx_load = 0;
reg [9:0] tx_data;
wire tx_tx;
coax_tx #(
.CLOCKS_PER_BIT(8)
) tx (
.clk(clk),
.load(tx_load),
.data(tx_data),
.tx(tx_tx)
);
reg rx_data_read = 0;
wire rx_data_available;
coax_rx #(
.CLOCKS_PER_BIT(8)
) dut (
.clk(clk),
.rx(tx_tx),
.data_read(rx_data_read),
.data_available(rx_data_available)
);
initial
begin
$dumpfile("coax_rx_tb.vcd");
$dumpvars(0, coax_rx_tb);
#8
tx_data = 10'b0000000101;
tx_load = 1;
#2 tx_load = 0;
#32
tx_data = 10'b1111111111;
tx_load = 1;
#2 tx_load = 0;
repeat(200) @(posedge clk);
rx_data_read = 1;
#4 rx_data_read = 0;
repeat(100) @(posedge clk);
rx_data_read = 1;
#4 rx_data_read = 0;
repeat(100) @(posedge clk);
$finish;
end
endmodule

View File

@@ -1,43 +0,0 @@
`default_nettype none
module coax_tx_bit_timer_tb();
reg clk = 0;
initial
begin
forever
begin
#1 clk <= ~clk;
end
end
reg reset = 0;
wire first_half;
wire second_half;
wire end_strobe;
coax_tx_bit_timer #(
.CLOCKS_PER_BIT(8)
) dut (
.clk(clk),
.reset(reset),
.first_half(first_half),
.second_half(second_half),
.end_strobe(end_strobe)
);
initial
begin
$dumpfile("coax_tx_bit_timer_tb.vcd");
$dumpvars(0, coax_tx_bit_timer_tb);
repeat(100) @(posedge clk);
reset = 1;
#2 reset = 0;
repeat(100) @(posedge clk);
$finish;
end
endmodule

View File

@@ -1,50 +0,0 @@
`default_nettype none
module coax_tx_tb();
reg clk = 0;
initial
begin
forever
begin
#1 clk <= ~clk;
end
end
reg load = 0;
reg [9:0] data;
wire tx;
wire active;
coax_tx #(
.CLOCKS_PER_BIT(8)
) dut (
.clk(clk),
.load(load),
.data(data),
.tx(tx),
.active(active)
);
initial
begin
$dumpfile("coax_tx_tb.vcd");
$dumpvars(0, coax_tx_tb);
#8
data = 10'b0000000101;
load = 1;
#2 load = 0;
#32
data = 10'b1111111111;
load = 1;
#2 load = 0;
repeat(1000) @(posedge clk);
$finish;
end
endmodule

View File

@@ -1,32 +0,0 @@
`default_nettype none
module hello_world_tb();
reg clk = 0;
initial
begin
forever
begin
#1 clk <= ~clk;
end
end
wire tx;
wire tx_active;
hello_world dut (
.clk(clk),
.tx(tx),
.tx_active(tx_active)
);
initial
begin
$dumpfile("hello_world_tb.vcd");
$dumpvars(0, hello_world_tb);
repeat(2000) @(posedge clk);
$finish;
end
endmodule