diff --git a/j1a/Makefile b/j1a/Makefile index 13b72be..b3c7cc7 100644 --- a/j1a/Makefile +++ b/j1a/Makefile @@ -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 diff --git a/j1a/icestorm/Makefile b/j1a/icestorm/Makefile index 2864872..82aaf1f 100644 --- a/j1a/icestorm/Makefile +++ b/j1a/icestorm/Makefile @@ -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 = .. diff --git a/j1a/verilog/async_in_filter.v b/j1a/icestorm/async_in_filter.v similarity index 78% rename from j1a/verilog/async_in_filter.v rename to j1a/icestorm/async_in_filter.v index d71ecd8..3714ec8 100644 --- a/j1a/verilog/async_in_filter.v +++ b/j1a/icestorm/async_in_filter.v @@ -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 diff --git a/j1a/icestorm/j1a.bin b/j1a/icestorm/j1a.bin index 0453a85..3e36628 100644 Binary files a/j1a/icestorm/j1a.bin and b/j1a/icestorm/j1a.bin differ diff --git a/j1a/icestorm/j1a.v b/j1a/icestorm/j1a.v index 08a71ce..6669bda 100644 --- a/j1a/icestorm/j1a.v +++ b/j1a/icestorm/j1a.v @@ -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), diff --git a/j1a/icestorm/j1a8k.bin b/j1a/icestorm/j1a8k.bin index 99b2cdc..92c4519 100644 Binary files a/j1a/icestorm/j1a8k.bin and b/j1a/icestorm/j1a8k.bin differ diff --git a/j1a/icestorm/j1a8k.v b/j1a/icestorm/j1a8k.v index a6f190c..0337d7b 100644 --- a/j1a/icestorm/j1a8k.v +++ b/j1a/icestorm/j1a8k.v @@ -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), diff --git a/j1a/icestorm/j4a.bin b/j1a/icestorm/j4a.bin index 91e56da..bc5199c 100644 Binary files a/j1a/icestorm/j4a.bin and b/j1a/icestorm/j4a.bin differ diff --git a/j1a/icestorm/j4a.v b/j1a/icestorm/j4a.v index 7dca8d7..36d74ed 100644 --- a/j1a/icestorm/j4a.v +++ b/j1a/icestorm/j4a.v @@ -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), diff --git a/j1a/icestorm/uart3.v b/j1a/icestorm/uart3.v new file mode 100644 index 0000000..388b24f --- /dev/null +++ b/j1a/icestorm/uart3.v @@ -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 diff --git a/j1a/shell.py b/j1a/shell.py index 97e6576..b809d63 100644 --- a/j1a/shell.py +++ b/j1a/shell.py @@ -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