Skip to content

Commit

Permalink
adds new buart, works at 921600
Browse files Browse the repository at this point in the history
Moved async_in_filter.v because it was annoying verilator, and it belongs in its new home, as it references ice specific hardware anyway.
  • Loading branch information
RGD2 committed May 2, 2017
1 parent 60872cd commit 241015a
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 20 deletions.
8 changes: 7 additions & 1 deletion j1a/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@ mackextload:

endif

.PHONY: connect clean bootstrap mackextload mackextunload macconnect
pcon:
$(info Use C-a C-t to toggle reset line as necessary)
$(info Use C-a C-x to exit. No shell.py features are available)
picocom -b 921600 /dev/ttyUSB1 --imap lfcrlf,crcrlf --omap delbs,crlf --send-cmd "ascii-xfr -s -l 30 -n"


.PHONY: connect sim_connect j4a_sim_connect clean bootstrap mackextload mackextunload macconnect linmodload pcon
6 changes: 3 additions & 3 deletions j1a/icestorm/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
VERILOGS = j1a.v uart.v ../verilog/j1.v ../verilog/stack2.v
VERILOGS = j1a.v async_in_filter.v uart3.v ../verilog/j1.v ../verilog/stack2.v

VERILOGS8k = j1a8k.v uart.v ../verilog/j1.v ../verilog/stack2.v
VERILOGS8k = j1a8k.v uart3.v async_in_filter.v ../verilog/j1.v ../verilog/stack2.v

VERILOGS8k4 = j4a.v uart.v ../verilog/j1.v ../verilog/stack2.v ../verilog/j4.v ../verilog/stack2pipe4.v ../verilog/greycount.v
VERILOGS8k4 = j4a.v uart3.v async_in_filter.v ../verilog/*.v

SUBDIRS = ..

Expand Down
20 changes: 10 additions & 10 deletions j1a/verilog/async_in_filter.v → j1a/icestorm/async_in_filter.v
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,31 @@ SB_IO #(.PIN_TYPE(6'b0000_00)) inpin (
.D_IN_0(onereg));
reg threereg, tworeg; always @(posedge clk) {threereg,tworeg} <= {tworeg,onereg};
// triple registering helps prevent metastability when synchronising an undefined signal into a clock domain.

parameter FILTERBITS = 5;
// Final part is somewhat of a digital moving average glitch filter, with a digital Schmidt trigger output.
// this one takes 24 ticks to set rd on.
// saturates after 31 sequential highs.
// Then will take 24 sequential lows to turn off.
// Saturating back on zero after the 31st.
reg [4:0] fltr;
wire [1:0] tops = fltr[4:3]; // top two bits are used to decide whether to change output state.
reg [FILTERBITS-1:0] fltr;
wire [1:0] tops = fltr[FILTERBITS-1:FILTERBITS-2]; // top two bits are used to decide whether to change output state.
// change the two above to change the timing.
// (increase fltr size for slower signals,
// decrease for faster. should be no less than three bits.)
wire incr = ~&flrt & threereg;
wire decr = |flrt & ~threereg;
wire incr = ~&fltr & threereg;
wire decr = |fltr & ~threereg;
wire setr = &tops;
wire clrr = ~tops[1] & ~tops[0];
wire clrr = ~|tops;
always @(posedge clk)
begin
case({incr,decr})
10: flrt <= flrt + 1;
01: flrt <= flrt - 1;
default: flrt <= flrt;
10: fltr <= fltr + 1;
01: fltr <= fltr - 1;
default: fltr <= fltr;
endcase
case({setr,clrr})
10: rd <= 1'b1;
01: rd <= 0'b0;
01: rd <= 1'b0;
default: rd <= rd;
endcase
end
Expand Down
Binary file modified j1a/icestorm/j1a.bin
Binary file not shown.
4 changes: 2 additions & 2 deletions j1a/icestorm/j1a.v
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,8 @@ module top(input pclk, output D1, output D2, output D3, output D4, output D5,
wire uart0_wr = io_wr_ & io_addr_[12];
wire uart0_rd = io_rd_ & io_addr_[12];
wire uart_RXD;
inpin _rcxd(.clk(clk), .pin(RXD), .rd(uart_RXD));
buart _uart0 (
async_in_filter _rcxd(.clk(clk), .pin(RXD), .rd(uart_RXD));
buart #(.BAUD(921600)) _uart0 (
.clk(clk),
.resetq(1'b1),
.rx(uart_RXD),
Expand Down
Binary file modified j1a/icestorm/j1a8k.bin
Binary file not shown.
4 changes: 2 additions & 2 deletions j1a/icestorm/j1a8k.v
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,8 @@ module top(input pclk,
wire uart0_wr = io_wr_ & io_addr_[12];
wire uart0_rd = io_rd_ & io_addr_[12];
wire uart_RXD;
inpin _rcxd(.clk(clk), .pin(RXD), .rd(uart_RXD));
buart _uart0 (
async_in_filter _rcxd(.clk(clk), .pin(RXD), .rd(uart_RXD));
buart #(.BAUD(921600)) _uart0 (
.clk(clk),
.resetq(1'b1),
.rx(uart_RXD),
Expand Down
Binary file modified j1a/icestorm/j4a.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion j1a/icestorm/j4a.v
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ module top(input pclk,
wire uart0_rd = io_rd_ & io_addr_[12];
wire uart_RXD;
async_in_filter _rcxd(.clk(clk), .pin(RXD), .rd(uart_RXD));
buart #(.CLOCK_DIVIDE(313)) _uart0 (
buart #(.BAUD(921600)) _uart0 (
.clk(clk),
.resetq(1'b1),
.rx(uart_RXD),
Expand Down
69 changes: 69 additions & 0 deletions j1a/icestorm/uart3.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
`default_nettype none

module buart(
input clk, // The master clock for this module
input resetq, // Synchronous reset, active low
input rx, // Incoming serial line
output tx, // Outgoing serial line
input rd, // read strobe -- used only to clear valid flag.
input wr, // write strobe
output reg valid, // Indicates a new byte is available. clears on read.
output reg busy, // Low when transmit line is idle.
input [7:0] tx_data, // Byte to transmit
output reg [7:0] rx_data, // *Most recent* byte received -- whether or not the last was collected.
output reg error // reception error
);
// you can override these on a per-port basis, looks like:
// buart #(.BAUD(115200)) _youruart (.clk(clk)...etc);
// or
// buart #(.CLOCK_DIVIDE(312)) _uart1 (...
// The latter might be better for designs with non-48MHz clocks.
parameter BAUD = 9600;
parameter CLKFREQ = 48000000; // frequency of incoming signal 'clk'
parameter CLOCK_DIVIDE = (CLKFREQ / (BAUD * 4)); // clock rate (48Mhz) / (baud rate (460800) * 4)
// will probably want to support at least down to 9600 baud, which will require a CLOCK_DIVIDE == 1250

localparam CDSIZE = $clog2(CLOCK_DIVIDE)+1; // one more to accomodate assumed signed arithmatic
reg [5:0] bytephase;
reg [CDSIZE-1:0] rxclkcounter;
wire rxqtick = rxclkcounter == CLOCK_DIVIDE; // strobes high one clk every 1/4 bit time
wire rxrst = rx & (~|bytephase); // rx goes low with the beginning of the start bit. synchronous to system clk, not sample clk.
always @(posedge clk) rxclkcounter <= rxrst | rxqtick ? 1 : rxclkcounter + 1; // initially held in reset
// very important: idle rx line holds rxrst asserted,
// this goes on *until* the start edge is found.
// thus synchronising further sampling to that edge, rather than remaining in phase with however it was reset.

wire rxstop = bytephase == 6'd40; // 11th sample 'tick' would have been at 42.
wire nonstarter;
always @(posedge clk) bytephase <= rxstop|nonstarter ? 0 : rxqtick ? bytephase + 1 : bytephase;
wire sample = (bytephase[1:0] == 2'b10) & rxqtick; // one clk for each of ten bits
// note sample is false while rxrst is true.
assign nonstarter = (bytephase == 6'd2) & rx; // start bit should still be low when sample strobes first.
// if it isn't, then it will go back to a rxrst state.

// after this point, we have a sample strobe, a rxstop strobe
reg [9:0] capture; always @(posedge clk) capture <= sample ? {rx, capture[9:1]} : capture;
// note bits are sent least-significant first.
wire startbit = capture[0]; // valid when rxstop strobes, and until rxrst releases for the next byte.
wire stopbit = capture[9];
wire good = stopbit&~startbit; // valid when rxstop is asserted. stop bit should be 1, start bit should have been zero.
always @(posedge clk)
begin
valid <= rd ? 1'b0 : rxstop & good ? 1'b1 : valid;
rx_data <= rxstop & good ? capture[8:1] : rx_data;
error <= nonstarter ? 1'b1 : rxstop ? ~good : error ;
end
// tx parts
reg [CDSIZE+1:0] txclkcounter; // note, two extra bits to accomodate a limit 4x as large.
wire txtick = txclkcounter == 4*CLOCK_DIVIDE; // ticks for a clk once every bit, not every quarter bit.
always @(posedge clk) txclkcounter <= txtick ? 1 : txclkcounter + 1;
// note txclkcounter never needs to be reset out-of-phase with itself.
reg [3:0] sentbits;
wire done = sentbits == 4'd10; // eventually stays 'done'. Reset to zero again when wr strobes.
always @(posedge clk) sentbits <= txtick & ~done ? sentbits + 1 : wr ? 4'd0 : sentbits ;
reg [9:0] sender;
// wr strobe might come any clk, not synchronous to txtick. No real need to force txtick to be synchronous to it either.
always @(posedge clk) sender <= wr ? {tx_data, 1'b0, 1'b1} : txtick ? {1'b1, sender[9:1]} : sender;
assign tx = sender[0]; // wr loads this 1, because tranmission doesn't start until the next txtick, whenever it arrives.
assign busy = ~done;
endmodule
2 changes: 1 addition & 1 deletion j1a/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def open_ser(self, port, speed):
except:
print("This tool needs PySerial, but it was not found")
sys.exit(1)
self.ser = serial.Serial(port, 4 * 115200, timeout=None, rtscts=0)
self.ser = serial.Serial(port, 921600, timeout=None, rtscts=0)

def reset(self, fullreset = True):
ser = self.ser
Expand Down

0 comments on commit 241015a

Please sign in to comment.