commit 8515162d03a7aafa6b9f4d109253d9b38575414a from: Benjamin Stürz date: Fri Feb 02 17:05:13 2024 UTC inital commit Signed-off-by: Benjamin Stürz commit - /dev/null commit + 8515162d03a7aafa6b9f4d109253d9b38575414a blob - /dev/null blob + 5d210ac7e7e5bba96d91669f9159c1fc57d61644 (mode 644) --- /dev/null +++ .gitignore @@ -0,0 +1,4 @@ +ulx3s.bit +ulx3s.json +ulx3s_out.config +design.json blob - /dev/null blob + 4d394a82bcc29895e1da9f1c69082c9f5c048a9a (mode 644) --- /dev/null +++ Makefile @@ -0,0 +1,34 @@ +.POSIX: + +CLOCKS = src/clk1.v +SRC = ${CLOCKS} src/sdram.v src/cpu.v src/top.v + +all: ulx3s.bit + +clean: + rm -f ${CLOCKS} ulx3s.bit ulx3s_out.config design.json + +flash: ulx3s.bit + fujprog ulx3s.bit + +flash-rom: ulx3s.bit + fujprog -j FLASH ulx3s.bit + +ulx3s.bit: ulx3s_out.config + ecppack ulx3s_out.config ulx3s.bit + +ulx3s_out.config: design.json ulx3s_v20.lpf + nextpnr-ecp5 --quiet \ + --top=top \ + --85k \ + --json design.json \ + --package CABGA381 \ + --lpf ulx3s_v20.lpf \ + --textcfg ulx3s_out.config + +design.json: ${SRC} + yosys -q -p 'synth_ecp5 -noccu2 -nomux -json design.json' ${SRC} + +src/clk1.v: + ecppll -i 25 -o 40 -n Clock1 -f $@ + blob - /dev/null blob + bbe26aa689f251fccea099b9b670fbd80eb37af7 (mode 644) --- /dev/null +++ isa @@ -0,0 +1,55 @@ +# Registers + +16 bit +8 GPRs (zero=0, sp=6, lr=7) +1 PC + +# Instructions + +|---------------------|---------------------|-------------------------------|---|--------------------------------------------| +| rep | instr | func | F | descr | +|---------------------|---------------------|-------------------------------|---|--------------------------------------------| +| 0000 0RRR 0RRR 0RRR | add rd, rs, rt | rd = rs + rt | R | Addition | +| 0000 0RRR 0RRR 1RRR | sub rd, rs, rt | rd = rs - rt | R | Subtraction | +| 0000 0RRR 1RRR 0RRR | and rd, rs, rt | rd = rs & rt | R | Logical AND | +| 0000 0RRR 1RRR 1RRR | or rd, rs, rt | rd = rs or rt | R | Logical OR | +| 0000 1RRR 0RRR 0RRR | lsh rd, rs, rt | rd = lshift(rs, rt) | R | Logical bi-directional shift | +| 0000 1RRR 0RRR 1RRR | xor rd, rs, rt | rd = rs ^ rt | R | Logical XOR | +| 0000 1RRR 1RRR 0RRR | slt rd, rs, rt | rd = rs < rt (signed) | R | Set if less than (signed) | +| 0000 1RRR 1RRR 1RRR | sltu rd, rs, rt | rd = rs < rt (unsigned) | R | Set if less than (unsigned) | +| 0001 0RRR 0RRR 0RRR | jalr rd, rt | rd = pc; pc = rt | R | Jump to Register and Link | +| 0001 0RRR 1RRR 0RRR | ud | | R | (undefined) | +| 0001 1RRR 0RRR 0RRR | ud | | R | | +| 0001 1RRR 1RRR 0RRR | ud | | R | | +| 0001 xRRR xRRR 1RRR | ud | | R | | +|---------------------|---------------------|-------------------------------|---|--------------------------------------------| +| 0010 0RRR IIII IIII | addi reg, simm8 | rd = rd + simm8 | I | Add w/ immediate | +| 0010 1RRR IIII IIII | lshi reg, simm8 | rd = lshift(rd, simm8) | I | Logical bi-directional shift w/ immediate | +| 0011 0RRR IIII IIII | lui rd, imm8 | rd = (imm8 << 8) | I | Load upper-immediate | +| 0011 1RRR IIII IIII | li rd, imm8 | rd = imm8 | I | Load lower-immediate | +|---------------------|---------------------|-------------------------------|---|--------------------------------------------| +| 0100 IRRR IIII IRRR | lw rd, [rt, simm6] | rd = *(rt + simm6) | L | Load word from memory | +| 0101 IRRR IIII IRRR | lbu rd, [rt, simm6] | rd = *(rt + simm6) | L | Load unsigned byte from memory (TODO) | +| 0110 IRRR IIII IRRR | lb rd, [rt, simm6] | rd = *(rt + simm6) | L | Load sign-extended byte from memory (TODO) | +| 0111 IRRR IIII IRRR | ud | | L | | +|---------------------|---------------------|-------------------------------|---|--------------------------------------------| +| 1000 IIII IRRR IRRR | sw rs, [rt, simm6] | *(rt + simm6 * 2) = rs | S | Store word to memory | +| 1001 IIII IRRR IRRR | sb rs, [rt, simm6] | *(rt + simm6) = rs | S | Store byte to memory (TODO) | +| 1010 IIII IRRR IRRR | beq rs, rt, simm6 | if (rs == rt) pc += simm6 * 2 | S | PC-relative branch if equal | +| 1011 IIII IRRR IRRR | bne rs, rt, simm6 | if (rs != rt) pc += simm6 * 2 | S | PC-relative branch if not equal | +|---------------------|---------------------|-------------------------------|---|--------------------------------------------| +| 110x xxxx xxxx xxxx | ud | | ? | | +|---------------------|---------------------|-------------------------------|---|--------------------------------------------| +| 1110 IIII IIII IIII | jal simm12 | lr = pc; pc += simm12 * 2 | J | PC-relative Jump and Link | +| 1111 IIII IIII IIII | j simm12 | pc += simm12 * 2 | J | PC-relative Jump | +|---------------------|---------------------|-------------------------------|---|--------------------------------------------| + +```c +uint16_t lshift(uint16_t a, int16_t b) { + if (b < 0) { + return a >> -b; + } else { + return a << b; + } +} +``` blob - /dev/null blob + 9249f3fc3e890c2c9c6c0e3788fc2773bbd6a23f (mode 644) --- /dev/null +++ src/clk1.v @@ -0,0 +1,46 @@ +// diamond 3.7 accepts this PLL +// diamond 3.8-3.9 is untested +// diamond 3.10 or higher is likely to abort with error about unable to use feedback signal +// cause of this could be from wrong CPHASE/FPHASE parameters +module Clock1 +( + input clkin, // 25 MHz, 0 deg + output clkout0, // 40 MHz, 0 deg + output locked +); +(* FREQUENCY_PIN_CLKI="25" *) +(* FREQUENCY_PIN_CLKOP="40" *) +(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) +EHXPLLL #( + .PLLRST_ENA("DISABLED"), + .INTFB_WAKE("DISABLED"), + .STDBY_ENABLE("DISABLED"), + .DPHASE_SOURCE("DISABLED"), + .OUTDIVIDER_MUXA("DIVA"), + .OUTDIVIDER_MUXB("DIVB"), + .OUTDIVIDER_MUXC("DIVC"), + .OUTDIVIDER_MUXD("DIVD"), + .CLKI_DIV(5), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(15), + .CLKOP_CPHASE(7), + .CLKOP_FPHASE(0), + .FEEDBK_PATH("CLKOP"), + .CLKFB_DIV(8) + ) pll_i ( + .RST(1'b0), + .STDBY(1'b0), + .CLKI(clkin), + .CLKOP(clkout0), + .CLKFB(clkout0), + .CLKINTFB(), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b1), + .PHASESTEP(1'b1), + .PHASELOADREG(1'b1), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked) + ); +endmodule blob - /dev/null blob + a904ee1746137195fafe16dad4a887efac2510b0 (mode 644) --- /dev/null +++ src/cpu-old.v @@ -0,0 +1,278 @@ +// Control Word +`define BIT_MEM_EN 0 +`define BIT_PC_INC 1 +`define BIT_ACC_WR 2 +`define BIT_ACC_EN 3 +`define BIT_LOAD_INSTR 4 +`define BIT_MAR_WR 5 +`define BIT_REG_WR 6 +`define BIT_ALU_EN 7 +`define BIT_PC_EN 8 +`define BIT_MAR_EN 9 +`define BIT_MEM_WR 10 +`define BIT_PC_WR 11 +`define BIT_FLAGS_WR 12 +`define BIT_TIMER_RST 14 +`define BIT_HLT 15 + +// Flags +`define BIT_ZERO 0 +`define BIT_CARRY 1 + +`define MEM_EN (16'b1 << `BIT_MEM_EN) +`define PC_INC (16'b1 << `BIT_PC_INC) +`define ACC_WR (16'b1 << `BIT_ACC_WR) +`define ACC_EN (16'b1 << `BIT_ACC_EN) +`define MAR_WR (16'b1 << `BIT_MAR_WR) +`define LOAD_INSTR (16'b1 << `BIT_LOAD_INSTR) +`define REG_WR (16'b1 << `BIT_REG_WR) +`define ALU_EN (16'b1 << `BIT_ALU_EN) +`define PC_EN (16'b1 << `BIT_PC_EN) +`define MAR_EN (16'b1 << `BIT_MAR_EN) +`define MEM_WR (16'b1 << `BIT_MEM_WR) +`define PC_WR (16'b1 << `BIT_PC_WR) +`define FLAGS_WR (16'b1 << `BIT_FLAGS_WR) +`define TIMER_RST (16'b1 << `BIT_TIMER_RST) +`define HLT (16'b1 << `BIT_HLT) + +`define ZERO (4'b1 << `BIT_ZERO) +`define CARRY (4'b1 << `BIT_CARRY) + +module ProgramCounter( + inout [11:0] addr, + input inc, + input en, + input wr, + input clk, + input rst + ); + + reg [11:0] value = 0; + + always@ (posedge clk or posedge rst) + begin + if (rst) + value <= 0; + else if (wr && !en) + value <= addr; + else if (inc) + value <= value + 1; + end + + assign addr = en && !wr ? value : 12'hzzz; + +endmodule // ProgramCounter + +module Register( + output reg [7:0] data_out = 0, + input [7:0] data_in, + input wr, + input clk, + input rst + ); + +always@ (posedge clk or posedge rst) + begin + if (rst) + data_out <= 0; + else if (wr) + data_out <= data_in; + end + +endmodule // Register + +module Accumulator( + inout [7:0] bus, + output [7:0] out, + input clk, + input rst, + input wr, + input en + ); + + reg [7:0] value = 0; + + + always@ (posedge clk or posedge rst) + begin + if (rst) + value <= 0; + else if (wr && !en) + value <= bus; + end + + assign out = value; + assign bus = (!wr && en) ? value : 8'hzz; +endmodule // Accumulator + +module InstructionDecoder( + input [3:0] timer, + input [7:0] instr, + input clk, + output reg [`BIT_HLT:0] control_word + ); + wire [`BIT_HLT:0] cw_instr [15:0] [15:2]; + + // hlt + assign cw_instr[4'b0000][4'b0010] = `HLT; + + // lda imm8 + assign cw_instr[4'b0001][4'b0010] = `PC_EN | `MEM_EN | `ACC_WR; + assign cw_instr[4'b0001][4'b0011] = `PC_INC | `TIMER_RST; + + // alu imm8 + assign cw_instr[4'b0010][4'b0010] = `PC_EN | `MEM_EN | `REG_WR; + assign cw_instr[4'b0010][4'b0011] = `PC_INC | `ALU_EN | `ACC_WR | `TIMER_RST; + + // rb imm12 + assign cw_instr[4'b0011][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR; + assign cw_instr[4'b0011][4'b0011] = `PC_INC | `MAR_EN | `MEM_EN | `ACC_WR | `TIMER_RST; + + // wb imm12 + assign cw_instr[4'b0100][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR; + assign cw_instr[4'b0100][4'b0011] = `PC_INC | `MAR_EN | `MEM_WR | `ACC_EN | `TIMER_RST; + + // jmp imm12 + assign cw_instr[4'b0101][4'b0010] = `PC_EN | `MEM_EN | `MAR_WR; + assign cw_instr[4'b0101][4'b0011] = `MAR_EN | `PC_WR | `TIMER_RST; + + always@ (negedge clk) + case (timer) + 4'b0000: control_word <= `PC_EN | `MEM_EN | `LOAD_INSTR; + 4'b0001: control_word <= `PC_INC; + default: control_word <= cw_instr[instr[7:4]][timer]; + endcase + +endmodule // InstructionDecoder + +module ALU( + input [7:0] in_a, + input [7:0] in_b, + input [3:0] funct, + input [3:0] flags_in, + output [7:0] out, + output [3:0] flags_out, + input en + ); + reg [8:0] result; + + always@ (*) + begin + case (funct) + 4'b0000: result = in_a + in_b; + 4'b0001: result = in_a - in_b; + 4'b0010: result = { 1'b0, in_a & in_b }; + 4'b0011: result = { 1'b0, in_a | in_b }; + 4'b0100: result = { 1'b0, in_a ^ in_b }; + 4'b0101: result = { 1'b0, in_a << in_b }; + 4'b0110: result = { 1'b0, in_a >> in_b }; + 4'b0111: result = { 1'b0, in_a >>> in_b }; + default: result = 9'bx; + endcase + end + + assign flags_out[`BIT_ZERO] = result[7:0] == 0; + assign flags_out[`BIT_CARRY] = result[8]; + assign out = en ? result[7:0] : 8'bz; +endmodule // ALU + +module CPU( + output [11:0] addr_out, + inout [7:0] bus, + output [7:0] debug, + output mem_wr, + output mem_en, + output reg hlt = 0, + input clk, + input rst + ); + wire [`BIT_HLT:0] control_word; + wire [7:0] instr; + wire [7:0] alu_in_a; + wire [7:0] alu_in_b; + wire [3:0] flags_alu; + reg [3:0] timer = 0; + reg [11:0] mar; + reg [3:0] flags; + + assign debug = instr; + + ProgramCounter _pc( + .addr(addr_out), + .inc(control_word[`BIT_PC_INC]), + .en(control_word[`BIT_PC_EN]), + .wr(control_word[`BIT_PC_WR]), + .clk(clk), + .rst(rst) + ); + + Register _ireg( + .data_in(bus), + .data_out(instr), + .wr(control_word[`BIT_LOAD_INSTR]), + .clk(clk), + .rst(rst) + ); + + InstructionDecoder _idec( + .instr(instr), + .clk(clk), + .timer(timer), + .control_word(control_word) + ); + + Accumulator _acc( + .bus(bus), + .out(alu_in_a), + .clk(clk), + .rst(rst), + .wr(control_word[`BIT_ACC_WR]), + .en(control_word[`BIT_ACC_EN]) + ); + + Register _reg( + .data_in(bus), + .data_out(alu_in_b), + .clk(clk), + .rst(rst), + .wr(control_word[`BIT_REG_WR]) + ); + + ALU _alu( + .in_a(alu_in_a), + .in_b(alu_in_b), + .funct(instr[3:0]), + .out(bus), + .flags_in(flags), + .flags_out(flags_alu), + .en(control_word[`BIT_ALU_EN]) + ); + + assign addr_out = control_word[`BIT_MAR_EN] ? mar : 12'hzzz; + assign mem_wr = control_word[`BIT_MEM_WR]; + assign mem_en = control_word[`BIT_MEM_EN]; + + always@ (posedge clk or posedge rst) + if (rst) + flags <= 0; + else if (control_word[`BIT_FLAGS_WR]) + flags <= flags_alu; + + always@ (posedge clk or posedge rst) + if (rst) + hlt <= 0; + else if (control_word[`BIT_HLT]) + hlt <= 1; + + always@ (posedge clk) + if (control_word[`BIT_MAR_WR]) + mar <= { instr[3:0], bus }; + + always@ (posedge clk or posedge rst) + if (rst) + timer <= 0; + else if (control_word[`BIT_TIMER_RST]) + timer <= 0; + else + timer <= timer + 1; +endmodule // CPU blob - /dev/null blob + d1e8028ade1f8c557cd08429fc3281279511c971 (mode 644) --- /dev/null +++ src/cpu.v @@ -0,0 +1,234 @@ +`define FMT_R 3'b000 +`define FMT_I 3'b001 +`define FMT_L 3'b010 +`define FMT_S 3'b011 +`define FMT_J 3'b100 +`define FMT_UD 3'b111 + +`define CWB_MEM_WR 0 +`define CWB_MEM_EN 1 +`define CWB_PC_WR 2 +`define CWB_IR_WR 3 +`define CWB_WB 4 + +`define CW_MEM_WR (16'b1 << `CWB_MEM_WR) +`define CW_MEM_EN (16'b1 << `CWB_MEM_EN) +`define CW_PC_WR (16'b1 << `CWB_PC_WR) +`define CW_IR_WR (16'b1 << `CWB_IR_WR) +`define CW_WB (16'b1 << `CWB_WB) + +function [15:0] lshift(input [15:0] value, input [15:0] shamt); + if (shamt[15] == 1'b0) + lshift = value << shamt; + else + lshift = value >> -shamt; +endfunction + +module ALU( + input [15:0] in1, + input [15:0] in2, + input [2:0] op, + output reg [15:0] out + ); + + wire signed [15:0] in1s = in1; + wire signed [15:0] in2s = in2; + + always@ (*) begin + case (op) + 3'b000: out = in1 + in2; + 3'b001: out = in1 - in2; + 3'b010: out = in1 & in2; + 3'b011: out = in1 | in2; + 3'b100: out = lshift(in1, in2); + 3'b101: out = in1 ^ in2; + 3'b110: out = { 15'b0, (in1 < in2) }; + 3'b111: out = { 15'b0, (in1s < in2s) }; + endcase + end +endmodule + +module Processor( + output [7:0] debug, + output reg [15:0] mem_addr, + inout [15:0] mem_data, + output mem_wr, + output mem_en, + input mem_busy, + input clk, + input rst + ); + + wire [15:0] alu_in2, alu_out; + reg [15:0] regs [7:1]; + reg [15:0] rd, pc, next_pc, instr; + reg [15:0] control_word; + reg [3:0] state = 0; + reg [2:0] ifmt; + reg [15:0] imm, imm2; + wire [2:0] rd_sel = instr[15:12] != 4'b1110 ? instr[10:8] : 3'h7; + wire [2:0] rs_sel = ifmt == `FMT_I ? instr[10:8] : instr[6:4]; + wire [2:0] rt_sel = instr[2:0]; + wire [2:0] alu_op = ifmt == `FMT_R ? { instr[11], instr[7], instr[3] } : { instr[11], 2'b00 }; + wire [15:0] rs = regs[rs_sel]; + wire [15:0] rt = regs[rt_sel]; + wire [15:0] alu_in1 = rs; + + assign debug = control_word[7:0]; + + ALU _alu( + .in1(alu_in1), + .in2(alu_in2), + .op(alu_op), + .out(alu_out) + ); + + always@ (posedge clk or posedge rst) begin + if (rst) + pc <= 16'b0; + else if (control_word[`CWB_PC_WR] ) + pc <= next_pc; + end + + always@ (posedge clk or posedge rst) begin + if (rst) + instr <= 0; + else if (control_word[`CWB_IR_WR]) + instr <= mem_data; + end + + always@ (negedge clk or posedge rst) begin + if (rst) + state <= 0; + else begin + if (mem_busy) + control_word <= 0; + else begin + case (state) + // Fetch + 4'b0000: begin + mem_addr <= pc; + next_pc <= pc + 2; + control_word <= `CW_MEM_EN | `CW_IR_WR | `CW_PC_WR; + state <= state + 1; + end + // Execute + 4'b0001: begin + casez (instr[15:12]) + // alu rd, rs, rt + 4'b0000: begin + rd <= alu_out; + control_word <= `CW_WB; + state <= 0; + end + // jalr rd, rt + 4'b0001: begin + next_pc <= rt; + rd <= pc; + control_word <= `CW_WB | `CW_PC_WR; + state <= 0; + end + // alui rd, imm + 4'b0010: begin + rd <= alu_out; + control_word <= `CW_WB; + state <= 0; + end + // lui/li rd, imm + 4'b0011: begin + rd <= instr[11] ? imm : (imm << 8); + control_word <= `CW_WB; + state <= 0; + end + // lw rd, [rt, imm] + 4'b0100: begin + mem_addr <= rt; + control_word <= `CW_MEM_EN; + state <= state + 1; + end + // TODO: lb, lbu + // sw rs, [rt, imm] + 4'b1000: begin + mem_addr <= rt; + control_word <= `CW_MEM_WR; + state <= 0; + end + // TODO: sb + // bcc rs, rt, imm + 4'b101?: begin + if ((rs == rt) ^ instr[12]) begin + next_pc <= pc + imm; + control_word <= `CW_PC_WR; + end + else control_word <= 0; + state <= 0; + end + // jal imm + 4'b1110: begin + rd <= pc; + next_pc <= pc + imm; + control_word <= `CW_WB | `CW_PC_WR; + state <= 0; + end + // j imm + 4'b1111: begin + next_pc <= pc + imm; + control_word <= `CW_PC_WR; + state <= 0; + end + endcase + end // case: 4'b0001 + // WB Memory + 4'b0010: begin + case (instr[15:12]) + 4'b0100: begin + rd <= mem_data; + control_word <= `CW_WB; + state <= 0; + end + default: state <= 0; + endcase + end + default: state <= 0; + endcase + end + end + end + + always@ (posedge clk) begin + if (control_word[`CWB_WB] && rd_sel != 0) + regs[rd_sel] <= rd; + end + + always@ (*) begin + casez (instr[15:12]) + 4'b000?: ifmt = `FMT_R; + 4'b001?: ifmt = `FMT_I; + 4'b01??: ifmt = `FMT_L; + 4'b10??: ifmt = `FMT_S; + 4'b110?: ifmt = `FMT_UD; + 4'b111?: ifmt = `FMT_J; + endcase + end + + always@ (*) begin + case (ifmt) + `FMT_I: imm2 = { {8{instr[7]}}, instr[7:0] }; + `FMT_L: imm2 = { {10{instr[11]}}, instr[11], instr[7:3] }; + `FMT_S: imm2 = { {10{instr[11]}}, instr[11:7], instr[3] }; + `FMT_J: imm2 = { {4{instr[11]}}, instr[11:0] }; + default: imm2 = 0; + endcase + casez (instr[15:12]) + 4'b1000: imm = imm2 << 1; + 4'b101?: imm = imm2 << 1; + 4'b111?: imm = imm2 << 1; + default: imm = imm2; + endcase + end + + assign alu_in2 = ifmt == `FMT_R ? rt : imm; + assign mem_wr = control_word[`CWB_MEM_WR]; + assign mem_en = control_word[`CWB_MEM_EN]; + assign mem_data = control_word[`CWB_MEM_WR] ? rs : 16'bz; +endmodule blob - /dev/null blob + 72565f08739c1c53fbdcfc0a29560fc275496882 (mode 644) --- /dev/null +++ src/sdram.v @@ -0,0 +1,330 @@ + +// SDRAM interface to AS4C32M16SB-7TCN +// 512 Mbit Single-Data-Rate SDRAM, 32Mx16 (8M x 16 x 4 Banks) + +// Matthias Koch, January 2022 + +// With a lot of inspiration from Mike Field, Hamsterworks: + +// https://web.archive.org/web/20190215130043/http://hamsterworks.co.nz/mediawiki/index.php/Simple_SDRAM_Controller +// https://web.archive.org/web/20190215130043/http://hamsterworks.co.nz/mediawiki/index.php/File:Verilog_Memory_controller_v0.1.zip + +// Note: You may need to change all values marked with *** when changing clock frequency. This is for 40 MHz. + +module SDRAM ( + + // Interface to SDRAM chip, fully registered + + output sd_clk, // Clock for SDRAM chip + output reg sd_cke, // Clock enabled + inout [15:0] sd_d, // Bidirectional data lines to/from SDRAM + output reg [12:0] sd_addr, // Address bus, multiplexed, 13 bits + output reg [1:0] sd_ba, // Bank select wires for 4 banks + output reg [1:0] sd_dqm, // Byte mask + output reg sd_cs, // Chip select + output reg sd_we, // Write enable + output reg sd_ras, // Row address select + output reg sd_cas, // Columns address select + + // Interface to processor + + input clk, + input resetn, + input [3:0] wmask, + input rd, + input [25:0] addr, + input [31:0] din, + output reg [31:0] dout, + output reg busy +); + + parameter sdram_startup_cycles = 10100; // *** -- 100us, plus a little more, @ 100MHz + parameter sdram_refresh_cycles = 195; // *** The refresh operation must be performed 8192 times within 64ms. --> One refresh every 7.8125 us. + // With a minimum clock of 25 MHz, this results in one refresh every 7.8125e-6 * 25e6 = 195 cycles. + + // ---------------------------------------------------------- + // -- Connections and buffer primitives + // ---------------------------------------------------------- + + assign sd_clk = ~clk; // Supply memory chip with a clock. + + wire [15:0] sd_data_in; // Bidirectional data from SDRAM + reg [15:0] sd_data_out; // Bidirectional data to SDRAM + reg sd_data_drive; // High: FPGA controls wires Low: SDRAM controls wires + + + `ifdef __ICARUS__ + + reg [15:0] sd_data_in_buffered; + assign sd_d = sd_data_drive ? sd_data_out : 16'bz; + always @(posedge clk) sd_data_in_buffered <= sd_d; + assign sd_data_in = sd_data_in_buffered; + + `else + + wire [15:0] sd_data_in_unbuffered; // To connect primitives internally + + TRELLIS_IO #(.DIR("BIDIR")) + sdio_tristate[15:0] ( + .B(sd_d), + .I(sd_data_out), + .O(sd_data_in_unbuffered), + .T(!sd_data_drive) + ); + + // Registering the input is important for stability and delays data arrival by one clock cycle. + IFS1P3BX dbi_ff[15:0] (.D(sd_data_in_unbuffered), .Q(sd_data_in), .SCLK(clk), .PD({16{sd_data_drive}})); + + `endif + // ---------------------------------------------------------- + // -- Configuration to initialise the SDRAM chip + // ---------------------------------------------------------- + + // Taken from https://github.com/rxrbln/picorv32/blob/master/picosoc/sdram.v + + localparam NO_WRITE_BURST = 1'b0; // 0=write burst enabled, 1=only single access write + localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed + localparam CAS_LATENCY = 3'd2; // 2 or 3 cycles allowed + localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved + localparam BURST_LENGTH = 3'b001; // 000=1, 001=2, 010=4, 011=8 + + localparam MODE = {3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH}; + + // ---------------------------------------------------------- + // -- All possible commands for the SDRAM chip + // ---------------------------------------------------------- + + // CS, RAS, CAS, WE + localparam CMD_INHIBIT = 4'b1111; + + localparam CMD_NOP = 4'b0111; + localparam CMD_BURST_TERMINATE = 4'b0110; + localparam CMD_READ = 4'b0101; + localparam CMD_WRITE = 4'b0100; + localparam CMD_ACTIVE = 4'b0011; + localparam CMD_PRECHARGE = 4'b0010; + localparam CMD_AUTO_REFRESH = 4'b0001; + localparam CMD_LOAD_MODE = 4'b0000; + + // ---------------------------------------------------------- + // -- States of the SDRAM controller + // ---------------------------------------------------------- + + localparam s_init_bit = 0; localparam s_init = 1 << s_init_bit ; + localparam s_idle_bit = 1; localparam s_idle = 1 << s_idle_bit ; + localparam s_activate_bit = 2; localparam s_activate = 1 << s_activate_bit ; + localparam s_read_1_bit = 3; localparam s_read_1 = 1 << s_read_1_bit ; + localparam s_read_2_bit = 4; localparam s_read_2 = 1 << s_read_2_bit ; + localparam s_read_3_bit = 5; localparam s_read_3 = 1 << s_read_3_bit ; + localparam s_read_4_bit = 6; localparam s_read_4 = 1 << s_read_4_bit ; + localparam s_read_5_bit = 7; localparam s_read_5 = 1 << s_read_5_bit ; + localparam s_write_1_bit = 8; localparam s_write_1 = 1 << s_write_1_bit ; + localparam s_write_2_bit = 9; localparam s_write_2 = 1 << s_write_2_bit ; + + localparam s_idle_in_6_bit = 10; localparam s_idle_in_6 = 1 << s_idle_in_6_bit ; + localparam s_idle_in_5_bit = 11; localparam s_idle_in_5 = 1 << s_idle_in_5_bit ; + localparam s_idle_in_4_bit = 12; localparam s_idle_in_4 = 1 << s_idle_in_4_bit ; + localparam s_idle_in_3_bit = 13; localparam s_idle_in_3 = 1 << s_idle_in_3_bit ; + localparam s_idle_in_2_bit = 14; localparam s_idle_in_2 = 1 << s_idle_in_2_bit ; + localparam s_idle_in_1_bit = 15; localparam s_idle_in_1 = 1 << s_idle_in_1_bit ; + + (* onehot *) + reg [15:0] state = s_init; + + // ---------------------------------------------------------- + // -- Access control wires + // ---------------------------------------------------------- + + reg [14:0] reset_counter = sdram_startup_cycles; + reg [7:0] refresh_counter = 0; + reg refresh_pending = 1; + reg rd_sticky = 0; + reg [3:0] wmask_sticky = 4'b0000; + + wire stillatwork = ~(state[s_read_5_bit] | state[s_write_2_bit]); + wire [8:0] refresh_counterN = refresh_counter - 1; + + // ---------------------------------------------------------- + // -- The memory controller + // ---------------------------------------------------------- + + always @(posedge clk) + if(!resetn) begin + state <= s_init; + reset_counter <= sdram_startup_cycles; // Counts backwards to zero + busy <= 0; // Technically, we are busy with initialisation, but there are no ongoing read or write requests + rd_sticky <= 0; + wmask_sticky <= 4'b0000; + sd_cke <= 0; + end else begin + + // FemtoRV32 pulses read and write lines high for exactly one clock cycle. + // Address and data lines keep stable until busy is released. + // Therefore: Take note of the requested read or write, and assert busy flag immediately. + + busy <= ((|wmask) | rd) | (busy & stillatwork ); + rd_sticky <= rd | (rd_sticky & stillatwork ); + wmask_sticky <= wmask | (wmask_sticky & {4{stillatwork}} ); + + // Schedule refreshes regularly + refresh_counter <= refresh_counterN[8] ? sdram_refresh_cycles : refresh_counterN[7:0]; + refresh_pending <= (refresh_pending & ~state[s_idle_bit]) | refresh_counterN[8]; + + (* parallel_case *) + case(1'b1) + + // Processor can already request the first read or write here, but has to wait then: + + state[s_init_bit]: begin + + //------------------------------------------------------------------------ + //-- This is the initial startup state, where we wait for at least 100us + //-- before starting the start sequence + //-- + //-- The initialisation is sequence is + //-- * de-assert SDRAM_CKE + //-- * 100us wait, + //-- * assert SDRAM_CKE + //-- * wait at least one cycle, + //-- * PRECHARGE + //-- * wait 2 cycles + //-- * REFRESH, + //-- * tREF wait + //-- * REFRESH, + //-- * tREF wait + //-- * LOAD_MODE_REG + //-- * 2 cycles wait + //------------------------------------------------------------------------ + + sd_ba <= 2'b00; // Reserved for future use in mode configuration + sd_dqm <= 2'b11; // Data bus in High-Z state + sd_data_drive <= 0; // Do not drive the data bus now + + case (reset_counter) // Counts from a large value down to zero + + 33: begin sd_cke <= 1; end + + // Ensure all rows are closed + 31: begin {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_PRECHARGE; sd_addr <= 13'b0010000000000; end + + // These refreshes need to be at least tRFC (63ns) apart + 23: begin {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_AUTO_REFRESH; end + 15: begin {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_AUTO_REFRESH; end + + // Now load the mode register + 7: begin {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_LOAD_MODE; sd_addr <= MODE; end + + default: {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; + endcase + + reset_counter <= reset_counter - 1; + if (reset_counter == 0) state <= s_idle; + end + + // New read or write requests from the processor may arrive in these states: + + //----------------------------------------------------- + //-- Additional NOPs to meet timing requirements + //----------------------------------------------------- + + state[s_idle_in_6_bit]: begin state <= s_idle_in_5; {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; end + state[s_idle_in_5_bit]: begin state <= s_idle_in_4; {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; end + state[s_idle_in_4_bit]: begin state <= s_idle_in_3; {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; end + state[s_idle_in_3_bit]: begin state <= s_idle_in_2; {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; end + state[s_idle_in_2_bit]: begin state <= s_idle_in_1; {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; end + state[s_idle_in_1_bit]: begin state <= s_idle; {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; end + + // Refresh cycle needs tRFC (63ns), so 6 idle cycles are needed @ 100MHz + + //----------------------------------------------------- + //-- Dispatch all possible actions while idling (NOP) + //----------------------------------------------------- + + state[s_idle_bit]: begin + sd_ba <= addr[23:22]; // Bank select, 2 bits + sd_addr <= {addr[25:24], addr[21:11]} ; // RA0-RA12: 8192 Row address + + {sd_cs, sd_ras, sd_cas, sd_we} <= refresh_pending ? CMD_AUTO_REFRESH : + (|wmask_sticky) | rd_sticky ? CMD_ACTIVE : + CMD_NOP; + + state <= refresh_pending ? s_idle_in_2 : // *** Experimental result: Direct transition to s_idle does not work @ 40 MHz, s_idle_in_1 is unstable, sd_idle_in_2 is fine. + (|wmask_sticky) | rd_sticky ? s_activate : + s_idle; + end + + // Busy flag is set while state machine is in the following states: + + //----------------------------------------------------- + //-- Opening the row ready for reads or writes + //----------------------------------------------------- + + state[s_activate_bit]: begin + sd_data_drive <= ~rd_sticky; // Drive or release bus early, before the SDRAM chip takes over to drive these lines + {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; + state <= rd_sticky ? s_read_1 : s_write_1; + end + + // RAS-to-CAS delay, also necessary for precharge, used in this state machine: 2 cycles. + // Specification of AS4C32M16SB-7TCN: 21 ns --> Good for 1/(21e-9 / 2) = 95.23 MHz + + //----------------------------------------------------- + //-- Processing the read transaction + //----------------------------------------------------- + + state[s_read_1_bit]: begin + sd_dqm <= 2'b00; // SDRAM chip shall drive the bus lines + {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_READ; + sd_addr <= {3'b001, addr[10:2], 1'b0}; // Bit 10: Auto-precharge. CA0-CA9: 1024 Column address. + state <= s_read_2; + end + + state[s_read_2_bit]: begin + {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; + state <= s_read_3; + end + + state[s_read_3_bit]: state <= s_read_4; + + + state[s_read_4_bit]: begin + dout[15:0] <= sd_data_in; + state <= s_read_5; + end + + // Busy is cleared when reaching this state, fulfilling the request: + + state[s_read_5_bit]: begin + dout[31:16] <= sd_data_in; + state <= s_idle; // *** Experimental result: Direct transition to s_idle is fine @ 40 MHz + end + + // Precharge (which is automatic here) needs 21 ns, therefore 2 idle cycles need to be inserted + + //----------------------------------------------------- + // -- Processing the write transaction + //----------------------------------------------------- + + state[s_write_1_bit]: begin + sd_addr <= {3'b001, addr[10:2], 1'b0}; // Bit 10: Auto-precharge. CA0-CA9: 1024 Column address. + sd_data_out <= din[15:0]; + sd_dqm <= ~wmask_sticky[1:0]; + {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_WRITE; + state <= s_write_2; + end + + // Busy is cleared when reaching this state, fulfilling the request: + + state[s_write_2_bit]: begin + sd_data_out <= din[31:16]; + sd_dqm <= ~wmask_sticky[3:2]; + {sd_cs, sd_ras, sd_cas, sd_we} <= CMD_NOP; + state <= s_idle_in_2; // *** Experimental result: s_idle_in_1 does not work @ 40 MHz, s_idle_in_2 is fine. + end + + // Write needs 14 ns internally, then Precharge needs 21 ns, therefore 3 idle cycles need to be inserted + + endcase + end + +endmodule blob - /dev/null blob + b46f46b08fb3efb36817319f1d5974843ac2b8db (mode 644) --- /dev/null +++ src/sdram_test.v @@ -0,0 +1,75 @@ + +module top( + output sdram_clk, + output sdram_cke, + output sdram_csn, + output sdram_wen, + output sdram_rasn, + output sdram_casn, + output [12:0] sdram_a, + output [1:0] sdram_ba, + output [1:0] sdram_dqm, + inout [15:0] sdram_d, + + input clk_25mhz, + input [6:0] btn, + input [3:0] sw, + output [7:0] led, + output wifi_gpio0 + ); + + reg [25:0] addr = 0; + reg [31:0] counter = 0; + wire [31:0] data; + wire wr, rd, clk_40mhz, rst; + + Clock1 _clk1( + .clkin(clk_25mhz), + .clkout0(clk_40mhz), + .locked() + ); + SDRAM _sdram( + .sd_clk(sdram_clk), + .sd_cke(sdram_cke), + .sd_d(sdram_d), + .sd_addr(sdram_a), + .sd_ba(sdram_ba), + .sd_dqm(sdram_dqm), + .sd_cs(sdram_csn), + .sd_we(sdram_wen), + .sd_ras(sdram_rasn), + .sd_cas(sdram_casn), + + .clk(clk_40mhz), + .resetn(!rst), + .wmask(wr ? 4'b0001 : 4'b0), + .rd(rd), + .addr(addr), + .din(counter), + .dout(data), + .busy(led[7]) + ); + + wire change_counter = btn[3] || btn[4]; + wire change_addr = btn[5] || btn[6]; + + wire [31:0] next_counter = btn[3] ? counter + 1 : counter - 1; + wire [25:0] next_addr = btn[5] ? addr - 4 : addr + 4; + + always@ (posedge change_counter or posedge rst) + if (rst) + counter <= 0; + else + counter <= next_counter; + + always@ (posedge change_addr or posedge rst) + if (rst) + addr <= 0; + else + addr <= next_addr; + + assign rd = btn[1]; + assign wr = btn[2]; + assign rst = ~btn[0]; + assign led[6:0] = data[6:0]; +endmodule blob - /dev/null blob + cdbd75268ed63f22f0c4aa2f2e8e3fdab70f02d5 (mode 644) --- /dev/null +++ src/top.v @@ -0,0 +1,141 @@ +module ClockDivider( + input rst, + input clk_in, + output clk_out + ); + + reg clk = 0; + reg [31:0] counter = 0; + + always@ (posedge clk_in or posedge rst) + begin + if (rst) + begin + counter <= 0; + clk <= 0; + end + else if (counter == 32'd1_000_000) + begin + counter <= 0; + clk <= ~clk; + end + else + counter <= counter + 1; + end + + assign clk_out = ~clk; +endmodule + +module top( + output sdram_clk, + output sdram_cke, + output sdram_csn, + output sdram_wen, + output sdram_rasn, + output sdram_casn, + output [12:0] sdram_a, + output [1:0] sdram_ba, + output [1:0] sdram_dqm, + inout [15:0] sdram_d, + + input clk_25mhz, + input [6:0] btn, + input [3:0] sw, + output reg [7:0] led, + output wifi_gpio0 +); + + wire [15:0] mem_addr, mem_data; + wire mem_wr, mem_en, mem_busy; + wire clk_40mhz, clk, rst; + wire sdram; + wire [31:0] sdram_dout; + reg [15:0] data; + + wire [15:0] irom [15:0]; + reg [15:0] ram [127:0]; + + Clock1 _clk1( + .clkin(clk_25mhz), + .clkout0(clk_40mhz), + .locked() + ); + + ClockDivider _clk( + .clk_in(clk_40mhz), + .clk_out(clk), + .rst(rst) + ); + + Processor _cpu( + .debug(), + .mem_addr(mem_addr), + .mem_data(mem_data), + .mem_wr(mem_wr), + .mem_en(mem_en), + .mem_busy(mem_busy), + .clk(clk), + .rst(rst) + ); + + SDRAM _sdram( + .sd_clk(sdram_clk), + .sd_cke(sdram_cke), + .sd_d(sdram_d), + .sd_addr(sdram_a), + .sd_ba(sdram_ba), + .sd_dqm(sdram_dqm), + .sd_cs(sdram_csn), + .sd_we(sdram_wen), + .sd_ras(sdram_rasn), + .sd_cas(sdram_casn), + + .clk(clk_40mhz), + .resetn(!rst), + .wmask(sdram && mem_wr ? 4'b0011 : 4'b0000), + .rd(sdram && mem_en), + .addr({ 18'b0, (mem_addr[7:0] << 1) }), + .din({ 16'b0, mem_data }), + .dout(sdram_dout), + .busy(mem_busy) + ); + + + always@ (posedge clk) + if (mem_wr && !mem_en) + case (mem_addr[15:8]) + 8'h10: ram[mem_addr[7:1]] <= mem_data; + 8'h80: led <= mem_data[7:0]; + endcase + + always@ (*) begin + case (mem_addr[15:8]) + 8'h00: data <= irom[mem_addr[4:1]]; + 8'h10: data <= ram[mem_addr[8:1]]; + default: data <= 16'hFFFF; + endcase + end + + assign sdram = mem_addr[15:8] == 8'h20; + + assign irom[4'h0] = 16'h3180; // lui r1, 0x80 + assign irom[4'h1] = 16'h3220; // lui r2, 0x20 + assign irom[4'h2] = 16'h4302; // l: lw r3, [r2] + assign irom[4'h3] = 16'h8031; // sw r3, [r1, 0] + assign irom[4'h4] = 16'h2301; // addi r3, 1 + assign irom[4'h5] = 16'h8032; // sw r3, [r2, 0] + assign irom[4'h6] = 16'hfffb; // j l + assign irom[4'h7] = 16'hffff; // + assign irom[4'h8] = 16'hffff; // + assign irom[4'h9] = 16'hffff; // + assign irom[4'hA] = 16'hffff; // + assign irom[4'hB] = 16'hffff; + assign irom[4'hC] = 16'hffff; + assign irom[4'hD] = 16'hffff; + assign irom[4'hE] = 16'hffff; + assign irom[4'hF] = 16'hffff; + + assign wifi_gpio0 = clk; + assign mem_data = mem_en && !mem_wr ? (sdram ? sdram_dout[15:0] : data) : 16'bz; + assign rst = btn[2]; +endmodule blob - /dev/null blob + ce2d0b6d05024d014fbe8360e8a0987e39bfa7a2 (mode 644) --- /dev/null +++ ulx3s_v20.lpf @@ -0,0 +1,455 @@ +BLOCK RESETPATHS; +BLOCK ASYNCPATHS; +## ULX3S v2.0 and v2.1 + +# The clock "usb" and "gpdi" sheet +LOCATE COMP "clk_25mhz" SITE "G2"; +IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33; +FREQUENCY PORT "clk_25mhz" 25 MHZ; + +# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash +# write to FLASH possible any time from JTAG: +SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=ENABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; +# write to FLASH possible from user bitstream, not possible form JTAG: +# SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; + +## USBSERIAL FTDI-FPGA serial port "usb" sheet +LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi +LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi +LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives +LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives +LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives +IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33; + +## LED indicators "blinkey" and "gpio" sheet +LOCATE COMP "led[7]" SITE "H3"; +LOCATE COMP "led[6]" SITE "E1"; +LOCATE COMP "led[5]" SITE "E2"; +LOCATE COMP "led[4]" SITE "D1"; +LOCATE COMP "led[3]" SITE "D2"; +LOCATE COMP "led[2]" SITE "C1"; +LOCATE COMP "led[1]" SITE "C2"; +LOCATE COMP "led[0]" SITE "B2"; +IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet +LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic) +LOCATE COMP "btn[1]" SITE "R1"; # FIRE1 +LOCATE COMP "btn[2]" SITE "T1"; # FIRE2 +LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18 +LOCATE COMP "btn[4]" SITE "V1"; # DOWN +LOCATE COMP "btn[5]" SITE "U1"; # LEFT +LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16 +IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## DIP switch "blinkey", "gpio" sheet +LOCATE COMP "sw[0]" SITE "E8"; # SW1 +LOCATE COMP "sw[1]" SITE "D8"; # SW2 +LOCATE COMP "sw[2]" SITE "D7"; # SW3 +LOCATE COMP "sw[3]" SITE "E7"; # SW4 +IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet +LOCATE COMP "oled_clk" SITE "P4"; +LOCATE COMP "oled_mosi" SITE "P3"; +LOCATE COMP "oled_dc" SITE "P1"; +LOCATE COMP "oled_resn" SITE "P2"; +LOCATE COMP "oled_csn" SITE "N2"; +IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SPI Flash chip "flash" sheet +LOCATE COMP "flash_csn" SITE "R2"; +LOCATE COMP "flash_mosi" SITE "W2"; +LOCATE COMP "flash_miso" SITE "V2"; +LOCATE COMP "flash_holdn" SITE "W1"; +LOCATE COMP "flash_wpn" SITE "Y2"; +#LOCATE COMP "flash_clk" SITE "U3"; +#LOCATE COMP "flash_csspin" SITE "AJ3"; +#LOCATE COMP "flash_initn" SITE "AG4"; +#LOCATE COMP "flash_done" SITE "AJ4"; +#LOCATE COMP "flash_programn" SITE "AH4"; +#LOCATE COMP "flash_cfg_select[0]" SITE "AM4"; +#LOCATE COMP "flash_cfg_select[1]" SITE "AL4"; +#LOCATE COMP "flash_cfg_select[2]" SITE "AK4"; +IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SD card "sdcard", "usb" sheet +LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14 +LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15 +LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2 +LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4 +LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12 +LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13 +LOCATE COMP "sd_wp" SITE "P5"; # not connected +LOCATE COMP "sd_cdn" SITE "N5"; # not connected +IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement +IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## ADC SPI (MAX11123) "analog", "ram" sheet +LOCATE COMP "adc_csn" SITE "R17"; +LOCATE COMP "adc_mosi" SITE "R16"; +LOCATE COMP "adc_miso" SITE "U16"; +LOCATE COMP "adc_sclk" SITE "P17"; +IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## Audio 4-bit DAC "analog", "gpio" sheet +# 4-bit mode can drive down to 75 ohm load impedance. +# Lower impedance leads to IO overload, +# FPGA will stop working and need reboot. +# For standard 17 ohm earphones: +# use bits 2,3 as input (High-Z) and drive only bits 0,1. +LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio) +LOCATE COMP "audio_l[2]" SITE "C3"; +LOCATE COMP "audio_l[1]" SITE "D3"; +LOCATE COMP "audio_l[0]" SITE "E4"; +LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio) +LOCATE COMP "audio_r[2]" SITE "D5"; +LOCATE COMP "audio_r[1]" SITE "B5"; +LOCATE COMP "audio_r[0]" SITE "A3"; +LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio) +LOCATE COMP "audio_v[2]" SITE "F5"; +LOCATE COMP "audio_v[1]" SITE "F2"; +LOCATE COMP "audio_v[0]" SITE "H5"; +IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## WiFi ESP-32 "wifi", "usb", "flash" sheet +# other pins are shared with GP/GN, SD card and JTAG +LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi +LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi +LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi +LOCATE COMP "wifi_gpio0" SITE "L2"; +LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED +LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX +LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX +# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active +IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## PCB antenna 433 MHz (may be also used for FM) "usb" sheet +LOCATE COMP "ant_433mhz" SITE "G1"; +IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Second USB port "US2" going directly into FPGA "usb", "ram" sheet +LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only +LOCATE COMP "usb_fpga_dn" SITE "F16"; +IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # differential bidirectional +LOCATE COMP "usb_fpga_bd_dn" SITE "E15"; +IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=4; +LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control +LOCATE COMP "usb_fpga_pu_dn" SITE "C12"; +IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; + +## JTAG ESP-32 "usb" sheet +# connected to FT231X and ESP-32 +# commented out because those are dedicated pins, not directly useable as GPIO +# but could be used by some vendor-specific JTAG bridging (boundary scan) module +#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives +#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits +#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives +#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives +#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SDRAM "ram" sheet +LOCATE COMP "sdram_clk" SITE "F19"; +LOCATE COMP "sdram_cke" SITE "F20"; +LOCATE COMP "sdram_csn" SITE "P20"; +LOCATE COMP "sdram_wen" SITE "T20"; +LOCATE COMP "sdram_rasn" SITE "R20"; +LOCATE COMP "sdram_casn" SITE "T19"; +LOCATE COMP "sdram_a[0]" SITE "M20"; +LOCATE COMP "sdram_a[1]" SITE "M19"; +LOCATE COMP "sdram_a[2]" SITE "L20"; +LOCATE COMP "sdram_a[3]" SITE "L19"; +LOCATE COMP "sdram_a[4]" SITE "K20"; +LOCATE COMP "sdram_a[5]" SITE "K19"; +LOCATE COMP "sdram_a[6]" SITE "K18"; +LOCATE COMP "sdram_a[7]" SITE "J20"; +LOCATE COMP "sdram_a[8]" SITE "J19"; +LOCATE COMP "sdram_a[9]" SITE "H20"; +LOCATE COMP "sdram_a[10]" SITE "N19"; +LOCATE COMP "sdram_a[11]" SITE "G20"; +LOCATE COMP "sdram_a[12]" SITE "G19"; +LOCATE COMP "sdram_ba[0]" SITE "P19"; +LOCATE COMP "sdram_ba[1]" SITE "N20"; +LOCATE COMP "sdram_dqm[0]" SITE "U19"; +LOCATE COMP "sdram_dqm[1]" SITE "E20"; +LOCATE COMP "sdram_d[0]" SITE "J16"; +LOCATE COMP "sdram_d[1]" SITE "L18"; +LOCATE COMP "sdram_d[2]" SITE "M18"; +LOCATE COMP "sdram_d[3]" SITE "N18"; +LOCATE COMP "sdram_d[4]" SITE "P18"; +LOCATE COMP "sdram_d[5]" SITE "T18"; +LOCATE COMP "sdram_d[6]" SITE "T17"; +LOCATE COMP "sdram_d[7]" SITE "U20"; +LOCATE COMP "sdram_d[8]" SITE "E19"; +LOCATE COMP "sdram_d[9]" SITE "D20"; +LOCATE COMP "sdram_d[10]" SITE "D19"; +LOCATE COMP "sdram_d[11]" SITE "C20"; +LOCATE COMP "sdram_d[12]" SITE "E18"; +LOCATE COMP "sdram_d[13]" SITE "F18"; +LOCATE COMP "sdram_d[14]" SITE "J18"; +LOCATE COMP "sdram_d[15]" SITE "J17"; +IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +# GPDI differential interface (Video) "gpdi" sheet +LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue + +LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue - +LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green + +LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green - +LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red + +LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red - +LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock + +LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock - +LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet + +LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet - +LOCATE COMP "gpdi_cec" SITE "A18"; +LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC +LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12 +IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet +# Pins enumerated gp[0-27], gn[0-27]. +# With differential mode enabled on Lattice, +# gp[] (+) are used, gn[] (-) are ignored from design +# as they handle inverted signal by default. +# To enable differential, rename LVCMOS33->LVCMOS33D +LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0 +LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0 +LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1 +LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1 +LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2 +LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2 +LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3 +LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3 +LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4 +LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4 +LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5 +LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5 +LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6 +LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6 +IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7 +LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7 +LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8 +LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8 +LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9 +LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9 +LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27 +LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10 +LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25 +LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26 +LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32 +LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33 +LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34 +LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35 +IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14 +LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14 +LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15 +LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15 +LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16 +LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16 +LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17 +LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17 +LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18 +LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18 +LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19 +LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19 +LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20 +LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20 +IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21 +LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21 +LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 D15->B15 +LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22 E15->C15 +LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23 +LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23 +LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24 +LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24 +LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 B15->D14 +LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 C15->E14 +LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26 +LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26 +LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27 +LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27 +IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## PROGRAMN (reload bitstream from FLASH, exit from bootloader) +# PCB v2.0.5 and higher +LOCATE COMP "user_programn" SITE "M4"; +IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5) +# on PCB v1.7 shutdown is not connected to FPGA +LOCATE COMP "shutdown" SITE "G16"; # FPGA receives +IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;