aboutsummaryrefslogtreecommitdiff
path: root/docs/j1/verilog
diff options
context:
space:
mode:
Diffstat (limited to 'docs/j1/verilog')
-rw-r--r--docs/j1/verilog/common.h3
-rw-r--r--docs/j1/verilog/j1.v123
-rw-r--r--docs/j1/verilog/stack.v22
-rw-r--r--docs/j1/verilog/testbench.v30
-rw-r--r--docs/j1/verilog/top.v9
-rw-r--r--docs/j1/verilog/uart.v180
-rw-r--r--docs/j1/verilog/xilinx-top.v215
7 files changed, 582 insertions, 0 deletions
diff --git a/docs/j1/verilog/common.h b/docs/j1/verilog/common.h
new file mode 100644
index 0000000..03da65d
--- /dev/null
+++ b/docs/j1/verilog/common.h
@@ -0,0 +1,3 @@
+`default_nettype none
+`define WIDTH 32
+`define DEPTH 4
diff --git a/docs/j1/verilog/j1.v b/docs/j1/verilog/j1.v
new file mode 100644
index 0000000..d69ca20
--- /dev/null
+++ b/docs/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/docs/j1/verilog/stack.v b/docs/j1/verilog/stack.v
new file mode 100644
index 0000000..e5cee8a
--- /dev/null
+++ b/docs/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/docs/j1/verilog/testbench.v b/docs/j1/verilog/testbench.v
new file mode 100644
index 0000000..2ec2b5e
--- /dev/null
+++ b/docs/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/docs/j1/verilog/top.v b/docs/j1/verilog/top.v
new file mode 100644
index 0000000..efcf297
--- /dev/null
+++ b/docs/j1/verilog/top.v
@@ -0,0 +1,9 @@
+module top(
+ input clk,
+ input resetq,
+ output [15:0] tail);
+ parameter FIRMWARE = "<firmware>";
+
+ j1 _j1 (.clk(clk), .resetq(resetq));
+
+endmodule
diff --git a/docs/j1/verilog/uart.v b/docs/j1/verilog/uart.v
new file mode 100644
index 0000000..4daac0f
--- /dev/null
+++ b/docs/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/docs/j1/verilog/xilinx-top.v b/docs/j1/verilog/xilinx-top.v
new file mode 100644
index 0000000..6695d77
--- /dev/null
+++ b/docs/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