From cf01b391440fc9de43597b907acfc22dba1aa15e Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 18 Jun 2017 14:38:03 +0200 Subject: Add j1 --- j1 | 1 - j1/verilog/common.h | 3 + j1/verilog/j1.v | 123 +++++++++++++++++++++++++++ j1/verilog/stack.v | 22 +++++ j1/verilog/testbench.v | 30 +++++++ j1/verilog/top.v | 9 ++ j1/verilog/uart.v | 180 ++++++++++++++++++++++++++++++++++++++++ j1/verilog/xilinx-top.v | 215 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 582 insertions(+), 1 deletion(-) delete mode 160000 j1 create mode 100644 j1/verilog/common.h create mode 100644 j1/verilog/j1.v create mode 100644 j1/verilog/stack.v create mode 100644 j1/verilog/testbench.v create mode 100644 j1/verilog/top.v create mode 100644 j1/verilog/uart.v create mode 100644 j1/verilog/xilinx-top.v (limited to 'j1/verilog') diff --git a/j1 b/j1 deleted file mode 160000 index 9114396..0000000 --- a/j1 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 911439641c002a8f7a6e306ce1b1d3fd4b389fd6 diff --git a/j1/verilog/common.h b/j1/verilog/common.h new file mode 100644 index 0000000..03da65d --- /dev/null +++ b/j1/verilog/common.h @@ -0,0 +1,3 @@ +`default_nettype none +`define WIDTH 32 +`define DEPTH 4 diff --git a/j1/verilog/j1.v b/j1/verilog/j1.v new file mode 100644 index 0000000..d69ca20 --- /dev/null +++ b/j1/verilog/j1.v @@ -0,0 +1,123 @@ +`include "common.h" + +module j1( + input wire clk, + input wire resetq, + + output wire io_wr, + output wire [15:0] mem_addr, + output wire mem_wr, + output wire [`WIDTH-1:0] dout, + input wire [`WIDTH-1:0] mem_din, + + input wire [`WIDTH-1:0] io_din, + + output wire [12:0] code_addr, + input wire [15:0] insn + ); + reg [`DEPTH-1:0] dsp; // Data stack pointer + reg [`DEPTH-1:0] dspN; + reg [`WIDTH-1:0] st0; // Top of data stack + reg [`WIDTH-1:0] st0N; + reg dstkW; // D stack write + + reg [12:0] pc, pcN; + reg [`DEPTH-1:0] rsp, rspN; + reg rstkW; // R stack write + wire [`WIDTH-1:0] rstkD; // R stack write value + reg reboot = 1; + wire [12:0] pc_plus_1 = pc + 1; + + assign mem_addr = st0N[15:0]; + assign code_addr = {pcN}; + + // The D and R stacks + wire [`WIDTH-1:0] st1, rst0; + stack #(.DEPTH(`DEPTH)) + dstack(.clk(clk), .resetq(resetq), .ra(dsp), .rd(st1), .we(dstkW), .wa(dspN), .wd(st0)); + stack #(.DEPTH(`DEPTH))rstack(.clk(clk), .resetq(resetq), .ra(rsp), .rd(rst0), .we(rstkW), .wa(rspN), .wd(rstkD)); + + always @* + begin + // Compute the new value of st0 + casez ({insn[15:8]}) + 8'b1??_?????: st0N = { {(`WIDTH - 15){1'b0}}, insn[14:0] }; // literal + 8'b000_?????: st0N = st0; // jump + 8'b010_?????: st0N = st0; // call + 8'b001_?????: st0N = st1; // conditional jump + 8'b011_?0000: st0N = st0; // ALU operations... + 8'b011_?0001: st0N = st1; + 8'b011_?0010: st0N = st0 + st1; + 8'b011_?0011: st0N = st0 & st1; + 8'b011_?0100: st0N = st0 | st1; + 8'b011_?0101: st0N = st0 ^ st1; + 8'b011_?0110: st0N = ~st0; + 8'b011_?0111: st0N = {`WIDTH{(st1 == st0)}}; + 8'b011_?1000: st0N = {`WIDTH{($signed(st1) < $signed(st0))}}; +`ifdef NOSHIFTER // `define NOSHIFTER in common.h to cut slice usage in half and shift by 1 only + 8'b011_?1001: st0N = st1 >> 1; + 8'b011_?1010: st0N = st1 << 1; +`else // otherwise shift by 1-any number of bits + 8'b011_?1001: st0N = st1 >> st0[4:0]; + 8'b011_?1010: st0N = st1 << st0[4:0]; +`endif + 8'b011_?1011: st0N = rst0; + 8'b011_?1100: st0N = mem_din; + 8'b011_?1101: st0N = io_din; + 8'b011_?1110: st0N = {{(`WIDTH - 8){1'b0}}, rsp, dsp}; + 8'b011_?1111: st0N = {`WIDTH{(st1 < st0)}}; + default: st0N = {`WIDTH{1'bx}}; + endcase + end + + wire func_T_N = (insn[6:4] == 1); + wire func_T_R = (insn[6:4] == 2); + wire func_write = (insn[6:4] == 3); + wire func_iow = (insn[6:4] == 4); + + wire is_alu = (insn[15:13] == 3'b011); + assign mem_wr = !reboot & is_alu & func_write; + assign dout = st1; + assign io_wr = !reboot & is_alu & func_iow; + + assign rstkD = (insn[13] == 1'b0) ? {{(`WIDTH - 14){1'b0}}, pc_plus_1, 1'b0} : st0; + + reg [`DEPTH-1:0] dspI, rspI; + always @* + begin + casez ({insn[15:13]}) + 3'b1??: {dstkW, dspI} = {1'b1, 4'b0001}; + 3'b001: {dstkW, dspI} = {1'b0, 4'b1111}; + 3'b011: {dstkW, dspI} = {func_T_N, {insn[1], insn[1], insn[1:0]}}; + default: {dstkW, dspI} = {1'b0, 4'b0000}; + endcase + dspN = dsp + dspI; + + casez ({insn[15:13]}) + 3'b010: {rstkW, rspI} = {1'b1, 4'b0001}; + 3'b011: {rstkW, rspI} = {func_T_R, {insn[3], insn[3], insn[3:2]}}; + default: {rstkW, rspI} = {1'b0, 4'b0000}; + endcase + rspN = rsp + rspI; + + casez ({reboot, insn[15:13], insn[7], |st0}) + 6'b1_???_?_?: pcN = 0; + 6'b0_000_?_?, + 6'b0_010_?_?, + 6'b0_001_?_0: pcN = insn[12:0]; + 6'b0_011_1_?: pcN = rst0[13:1]; + default: pcN = pc_plus_1; + endcase + end + + always @(negedge resetq or posedge clk) + begin + if (!resetq) begin + reboot <= 1'b1; + { pc, dsp, st0, rsp } <= 0; + end else begin + reboot <= 0; + { pc, dsp, st0, rsp } <= { pcN, dspN, st0N, rspN }; + end + end +endmodule diff --git a/j1/verilog/stack.v b/j1/verilog/stack.v new file mode 100644 index 0000000..e5cee8a --- /dev/null +++ b/j1/verilog/stack.v @@ -0,0 +1,22 @@ +`include "common.h" + +module stack + #(parameter DEPTH=4) + (input wire clk, + /* verilator lint_off UNUSED */ + input wire resetq, + /* verilator lint_on UNUSED */ + input wire [DEPTH-1:0] ra, + output wire [`WIDTH-1:0] rd, + input wire we, + input wire [DEPTH-1:0] wa, + input wire [`WIDTH-1:0] wd); + + reg [`WIDTH-1:0] store[0:(2**DEPTH)-1]; + + always @(posedge clk) + if (we) + store[wa] <= wd; + + assign rd = store[ra]; +endmodule diff --git a/j1/verilog/testbench.v b/j1/verilog/testbench.v new file mode 100644 index 0000000..2ec2b5e --- /dev/null +++ b/j1/verilog/testbench.v @@ -0,0 +1,30 @@ +`timescale 1ns/1ps +`default_nettype none + +module testbench(); + + reg clk; + reg resetq; + integer t; + + top #(.FIRMWARE("build/firmware/")) dut(.clk(clk), .resetq(resetq)); + + initial begin + clk = 1; + t = 0; + resetq = 0; + #1; + resetq = 1; + + $dumpfile("test.vcd"); + $dumpvars(0, dut); + end + + always #5.0 clk = ~clk; + + always @(posedge clk) begin + t <= t + 1; + if (t == 300) + $finish; + end +endmodule diff --git a/j1/verilog/top.v b/j1/verilog/top.v new file mode 100644 index 0000000..efcf297 --- /dev/null +++ b/j1/verilog/top.v @@ -0,0 +1,9 @@ +module top( + input clk, + input resetq, + output [15:0] tail); + parameter FIRMWARE = ""; + + j1 _j1 (.clk(clk), .resetq(resetq)); + +endmodule diff --git a/j1/verilog/uart.v b/j1/verilog/uart.v new file mode 100644 index 0000000..4daac0f --- /dev/null +++ b/j1/verilog/uart.v @@ -0,0 +1,180 @@ +`default_nettype none + +module baudgen( + input wire clk, + input wire resetq, + input wire [31:0] baud, + input wire restart, + output wire ser_clk); + parameter CLKFREQ = 1000000; + + wire [38:0] aclkfreq = CLKFREQ; + reg [38:0] d; + wire [38:0] dInc = d[38] ? ({4'd0, baud}) : (({4'd0, baud}) - aclkfreq); + wire [38:0] dN = restart ? 0 : (d + dInc); + wire fastclk = ~d[38]; + assign ser_clk = fastclk; + + always @(negedge resetq or posedge clk) + begin + if (!resetq) begin + d <= 0; + end else begin + d <= dN; + end + end +endmodule + +/* + +-----+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---- + | | | | | | | | | | | | + |start| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |stop1|stop2| + | | | | | | | | | | | ? | + +-----+-----+-----+-----+-----+-----+-----+-----+-----+ + + +*/ + +module uart( + input wire clk, // System clock + input wire resetq, + + // Outputs + output wire uart_busy, // High means UART is transmitting + output reg uart_tx, // UART transmit wire + // Inputs + input wire [31:0] baud, + input wire uart_wr_i, // Raise to transmit byte + input wire [7:0] uart_dat_i // 8-bit data +); + parameter CLKFREQ = 1000000; + + reg [3:0] bitcount; + reg [8:0] shifter; + + assign uart_busy = |bitcount; + wire sending = |bitcount; + + wire ser_clk; + + wire starting = uart_wr_i & ~uart_busy; + baudgen #(.CLKFREQ(CLKFREQ)) _baudgen( + .clk(clk), + .resetq(resetq), + .baud(baud), + .restart(1'b0), + .ser_clk(ser_clk)); + + always @(negedge resetq or posedge clk) + begin + if (!resetq) begin + uart_tx <= 1; + bitcount <= 0; + shifter <= 0; + end else begin + if (starting) begin + shifter <= { uart_dat_i[7:0], 1'b0 }; + bitcount <= 1 + 8 + 1; + end + + if (sending & ser_clk) begin + { shifter, uart_tx } <= { 1'b1, shifter }; + bitcount <= bitcount - 4'd1; + end + end + end + +endmodule + +module rxuart( + input wire clk, + input wire resetq, + input wire [31:0] baud, + input wire uart_rx, // UART recv wire + input wire rd, // read strobe + output wire valid, // has data + output wire [7:0] data); // data + parameter CLKFREQ = 1000000; + + reg [4:0] bitcount; + reg [7:0] shifter; + + // On starting edge, wait 3 half-bits then sample, and sample every 2 bits thereafter + + wire idle = &bitcount; + wire sample; + reg [2:0] hh = 3'b111; + wire [2:0] hhN = {hh[1:0], uart_rx}; + wire startbit = idle & (hhN[2:1] == 2'b10); + wire [7:0] shifterN = sample ? {hh[1], shifter[7:1]} : shifter; + + wire ser_clk; + baudgen #(.CLKFREQ(CLKFREQ)) _baudgen( + .clk(clk), + .baud({baud[30:0], 1'b0}), + .resetq(resetq), + .restart(startbit), + .ser_clk(ser_clk)); + + assign valid = (bitcount == 18); + reg [4:0] bitcountN; + always @* + if (startbit) + bitcountN = 0; + else if (!idle & !valid & ser_clk) + bitcountN = bitcount + 5'd1; + else if (valid & rd) + bitcountN = 5'b11111; + else + bitcountN = bitcount; + + // 3,5,7,9,11,13,15,17 + assign sample = (bitcount > 2) & bitcount[0] & !valid & ser_clk; + assign data = shifter; + + always @(negedge resetq or posedge clk) + begin + if (!resetq) begin + hh <= 3'b111; + bitcount <= 5'b11111; + shifter <= 0; + end else begin + hh <= hhN; + bitcount <= bitcountN; + shifter <= shifterN; + end + end +endmodule + +module buart( + input wire clk, + input wire resetq, + input wire [31:0] baud, + input wire rx, // recv wire + output wire tx, // xmit wire + input wire rd, // read strobe + input wire wr, // write strobe + output wire valid, // has recv data + output wire busy, // is transmitting + input wire [7:0] tx_data, + output wire [7:0] rx_data // data +); + parameter CLKFREQ = 1000000; + + rxuart #(.CLKFREQ(CLKFREQ)) _rx ( + .clk(clk), + .resetq(resetq), + .baud(baud), + .uart_rx(rx), + .rd(rd), + .valid(valid), + .data(rx_data)); + uart #(.CLKFREQ(CLKFREQ)) _tx ( + .clk(clk), + .resetq(resetq), + .baud(baud), + .uart_busy(busy), + .uart_tx(tx), + .uart_wr_i(wr), + .uart_dat_i(tx_data)); +endmodule diff --git a/j1/verilog/xilinx-top.v b/j1/verilog/xilinx-top.v new file mode 100644 index 0000000..6695d77 --- /dev/null +++ b/j1/verilog/xilinx-top.v @@ -0,0 +1,215 @@ +`default_nettype none + + +module bram_tdp #( + parameter DATA = 72, + parameter ADDR = 10 +) ( + // Port A + input wire a_clk, + input wire a_wr, + input wire [ADDR-1:0] a_addr, + input wire [DATA-1:0] a_din, + output reg [DATA-1:0] a_dout, + + // Port B + input wire b_clk, + input wire b_wr, + input wire [ADDR-1:0] b_addr, + input wire [DATA-1:0] b_din, + output reg [DATA-1:0] b_dout +); + +// Shared memory +reg [DATA-1:0] mem [(2**ADDR)-1:0]; + initial begin + $readmemh("../build/firmware/demo0.hex", mem); + end + +// Port A +always @(posedge a_clk) begin + a_dout <= mem[a_addr]; + if(a_wr) begin + a_dout <= a_din; + mem[a_addr] <= a_din; + end +end + +// Port B +always @(posedge b_clk) begin + b_dout <= mem[b_addr]; + if(b_wr) begin + b_dout <= b_din; + mem[b_addr] <= b_din; + end +end + +endmodule + +// A 16Kbyte RAM (4096x32) with one write port and one read port +module ram16k0( + input wire clk, + + input wire[15:0] a_addr, + output wire[31:0] a_q, + input wire[31:0] a_d, + input wire a_wr, + + input wire[12:0] b_addr, + output wire[15:0] b_q); + + //synthesis attribute ram_style of mem is block + reg [31:0] mem[0:4095]; //pragma attribute mem ram_block TRUE + initial begin + $readmemh("../build/firmware/demo0.hex", mem); + end + + always @ (posedge clk) + if (a_wr) + mem[a_addr[13:2]] <= a_d; + + reg [15:0] a_addr_; + always @ (posedge clk) + a_addr_ <= a_addr; + assign a_q = mem[a_addr_[13:2]]; + + reg [12:0] raddr_reg; + always @ (posedge clk) + raddr_reg <= b_addr; + wire [31:0] insn32 = mem[raddr_reg[12:1]]; + assign b_q = raddr_reg[0] ? insn32[31:16] : insn32[15:0]; +endmodule + +module ram16k( + input wire clk, + + input wire[15:0] a_addr, + output wire[31:0] a_q, + input wire[31:0] a_d, + input wire a_wr, + + input wire[12:0] b_addr, + output wire[15:0] b_q); + + wire [31:0] insn32; + + bram_tdp #(.DATA(32), .ADDR(12)) nram ( + .a_clk(clk), + .a_wr(a_wr), + .a_addr(a_addr[13:2]), + .a_din(a_d), + .a_dout(a_q), + + .b_clk(clk), + .b_wr(1'b0), + .b_addr(b_addr[12:1]), + .b_din(32'd0), + .b_dout(insn32)); + + reg ba_; + always @(posedge clk) + ba_ <= b_addr[0]; + assign b_q = ba_ ? insn32[31:16] : insn32[15:0]; + +endmodule + + +module top( + input wire CLK, + output wire DUO_LED, + input wire DUO_SW1, + input wire RXD, + output wire TXD, + input wire DTR + ); + localparam MHZ = 40; + + wire fclk; + + DCM_CLKGEN #( + .CLKFX_MD_MAX(0.0), // Specify maximum M/D ratio for timing anlysis + .CLKFX_DIVIDE(32), // Divide value - D - (1-256) + .CLKFX_MULTIPLY(MHZ), // Multiply value - M - (2-256) + .CLKIN_PERIOD(31.25), // Input clock period specified in nS + .STARTUP_WAIT("FALSE") // Delay config DONE until DCM_CLKGEN LOCKED (TRUE/FALSE) + ) + DCM_CLKGEN_inst ( + .CLKFX(fclk), // 1-bit output: Generated clock output + .CLKIN(CLK), // 1-bit input: Input clock + .FREEZEDCM(0), // 1-bit input: Prevents frequency adjustments to input clock + .PROGCLK(0), // 1-bit input: Clock input for M/D reconfiguration + .PROGDATA(0), // 1-bit input: Serial data input for M/D reconfiguration + .PROGEN(0), // 1-bit input: Active high program enable + .RST(0) // 1-bit input: Reset input pin + ); + + reg [25:0] counter; + always @(posedge fclk) + counter <= counter + 26'd1; + assign DUO_LED = counter[25]; + + // ------------------------------------------------------------------------ + + wire uart0_valid, uart0_busy; + wire [7:0] uart0_data; + wire uart0_rd, uart0_wr; + reg [31:0] baud = 32'd115200; + wire UART0_RX; + buart #(.CLKFREQ(MHZ * 1000000)) _uart0 ( + .clk(fclk), + .resetq(1'b1), + .baud(baud), + .rx(RXD), + .tx(TXD), + .rd(uart0_rd), + .wr(uart0_wr), + .valid(uart0_valid), + .busy(uart0_busy), + .tx_data(dout_[7:0]), + .rx_data(uart0_data)); + + wire [15:0] mem_addr; + wire [31:0] mem_din; + wire mem_wr; + wire [31:0] dout; + + wire [12:0] code_addr; + wire [15:0] insn; + + wire io_wr; + + wire resetq = DTR; + + j1 _j1 ( + .clk(fclk), + .resetq(resetq), + + .io_wr(io_wr), + .mem_addr(mem_addr), + .mem_wr(mem_wr), + .mem_din(mem_din), + .dout(dout), + .io_din({16'd0, uart0_data, 4'd0, DTR, uart0_valid, uart0_busy, DUO_SW1}), + + .code_addr(code_addr), + .insn(insn) + ); + + ram16k ram(.clk(fclk), + .a_addr(mem_addr), + .a_q(mem_din), + .a_wr(mem_wr), + .a_d(dout), + .b_addr(code_addr), + .b_q(insn)); + + reg io_wr_; + reg [15:0] mem_addr_; + reg [31:0] dout_; + always @(posedge fclk) + {io_wr_, mem_addr_, dout_} <= {io_wr, mem_addr, dout}; + + assign uart0_wr = io_wr_ & (mem_addr_ == 16'h0000); + assign uart0_rd = io_wr_ & (mem_addr_ == 16'h0002); + +endmodule -- cgit v1.2.3