自作CPUへのSDRAMの組み込み
自作CPU Odeeen へ、SDRAMを組み込んだ。
table:Odeeen メモリマップ
Begin End サイズ 説明
00000000 0003ffff 256KB ブート用のファームウェア
40000000 4fffffff 64MB メインメモリ(SDRAM)
f0000000 f0000000 1 UART データレジスタ
f0000004 f0000004 1 UART コントロールレジスタ
f0001000 f0001000 1 LED コントロールレジスタ
SDRAMモジュールも Zucker SOC のものをそのまま利用できた。ありがたや。
SDRAMのタイミングがシビアなせいか、1の書き方だとうまく動かなくて、2の書き方だとうまく動いた。後で深掘りしたい。
code:verilog
// 1 => NG
assign sdram_en = (mem_addr >= 32'h40000000 && mam_addr <= 32'h4fffffff) ? 1'b1 : 1'b0;
// 2 => OK
assign sdram_en = ((mem_addr & 32'hf000_0000) == 32'h4000_0000) ? 1'b1 : 1'b0;
テストプログラム
code:firmware/mem_test.S
//---------------------------------------------------------
// SDRAM メモリ読み書きテスト
//
// 0x40000000 番地から始まる SDRAM にデータを書き込み、
// そこから読み出したデータを UART へ送信する。
//---------------------------------------------------------
.text
.globl _start
_start:
lui gp, 0xf0000 // UARTアクセス gp
lui tp, 0xf0001 // LEDアクセス用 gp
li s0, 0x40000000 // データ領域開始アドレス(SDRAM)
// SDRAM へデータを格納して...
li t0, 'A'
sw t0, 0(s0)
li t0, 'B'
sw t0, 4(s0)
li t0, 'C'
sw t0, 8(s0)
loop:
// SDRAM から読み出したデータを UART へ送信
lw a0, 0(s0)
sw a0, 0(tp)
call putc
call sleep
lw a0, 4(s0)
sw a0, 0(tp)
call putc
call sleep
lw a0, 8(s0)
sw a0, 0(tp)
call putc
call sleep
j loop
//---------------------------------------------------------
// getc: UARTから受信データを読み込む
//---------------------------------------------------------
getc:
// 受信データが来るまで待機
lw t0, UART_CTRL_OFFSET(x3)
li t1, 1
beq t0, t1, getc_break
j getc
getc_break:
lw a0, UART_DATA_OFFSET(x3)
ret
//---------------------------------------------------------
// putc: UARTへ送信データを書き込む
//---------------------------------------------------------
putc:
sw a0, UART_DATA_OFFSET(x3)
putc_wait:
// 送信が終わるまで待機
lw t0, UART_CTRL_OFFSET(x3)
li t2, 2 // 送信中
li t3, 3 // 送信中かつ受信済
beq t0, t2, putc_wait
beq t0, t3, putc_wait
putc_break:
ret
//---------------------------------------------------------
// だいたい1秒間スリープ
//---------------------------------------------------------
sleep:
li t0, 0
sleep_loop:
addi t0, t0, 1
li t1, 1000000
beq t0, t1, sleep_break
j sleep_loop
sleep_break:
ret
修正箇所の diff
全体の差分は以下の通り。
code:diff
diff --git a/Makefile b/Makefile
index cc9ae0d..7efbba9 100644
--- a/Makefile
+++ b/Makefile
@@ -19,8 +19,8 @@ ulx3s.bit: ulx3s_out.config firmware/firmware.hex
ulx3s_out.config: odeeen.json
nextpnr-ecp5 --85k --json odeeen.json --lpf rtl/ulx3s_v20.lpf --textcfg ulx3s_out.config
-odeeen.json: rtl/cpu.sv rtl/ulx3s_top.sv rtl/bram_controller.sv rtl/uart.v firmware/firmware_seed.hex
- yosys -p "hierarchy -top ulx3s_top" -p "synth_ecp5 -json odeeen.json" rtl/cpu.sv rtl/bram_controller.sv rtl/ulx3s_top.sv rtl/uart.v
+odeeen.json: rtl/cpu.sv rtl/ulx3s_top.sv rtl/bram_controller.sv rtl/sdram.v rtl/uart.v firmware/firmware_seed.hex
+ yosys -p "hierarchy -top ulx3s_top" -p "synth_ecp5 -json odeeen.json" rtl/cpu.sv rtl/bram_controller.sv rtl/sdram.v rtl/ulx3s_top.sv rtl/uart.v
prog: ulx3s.bit
fujprog -j SRAM ulx3s.bit
@@ -31,7 +31,7 @@ prog_flash: ulx3s.bit
test:
cd rtl && iverilog -g 2012 -s cpu_test cpu_test.sv cpu.sv bram_controller.sv && ./a.out
-FIRMWARE_TARGET = helloworld.S
+FIRMWARE_TARGET = mem_test.S
firmware/firmware.hex: firmware/$(FIRMWARE_TARGET)
riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -nostdlib -Wl,-Ttext=0x00000000 $< -o firmware/firmware.elf
diff --git a/firmware/mem_test.S b/firmware/mem_test.S
new file mode 100644
index 0000000..e480bcc
--- /dev/null
+++ b/firmware/mem_test.S
@@ -0,0 +1,83 @@
+#define UART_DATA_OFFSET 0
+#define UART_CTRL_OFFSET 4
+
+//---------------------------------------------------------
+// SDRAM メモリ読み書きテスト
+//
+// 0x40000000 番地から始まる SDRAM にデータを書き込み、
+// そこから読み出したデータを UART へ送信する。
+//---------------------------------------------------------
+ .text
+ .globl _start
+_start:
+ lui gp, 0xf0000 // UARTアクセス gp
+ lui tp, 0xf0001 // LEDアクセス用 gp
+ li s0, 0x40000000 // データ領域開始アドレス(SDRAM)
+
+ // SDRAM へデータを格納して...
+ li t0, 'A'
+ sw t0, 0(s0)
+ li t0, 'B'
+ sw t0, 4(s0)
+ li t0, 'C'
+ sw t0, 8(s0)
+
+loop:
+ // SDRAM から読み出したデータを UART へ送信
+ lw a0, 0(s0)
+ sw a0, 0(tp)
+ call putc
+ call sleep
+
+ lw a0, 4(s0)
+ sw a0, 0(tp)
+ call putc
+ call sleep
+
+ lw a0, 8(s0)
+ sw a0, 0(tp)
+ call putc
+ call sleep
+
+ j loop
+
+//---------------------------------------------------------
+// getc: UARTから受信データを読み込む
+//---------------------------------------------------------
+getc:
+ // 受信データが来るまで待機
+ lw t0, UART_CTRL_OFFSET(x3)
+ li t1, 1
+ beq t0, t1, getc_break
+ j getc
+getc_break:
+ lw a0, UART_DATA_OFFSET(x3)
+ ret
+
+//---------------------------------------------------------
+// putc: UARTへ送信データを書き込む
+//---------------------------------------------------------
+putc:
+ sw a0, UART_DATA_OFFSET(x3)
+putc_wait:
+ // 送信が終わるまで待機
+ lw t0, UART_CTRL_OFFSET(x3)
+ li t2, 2 // 送信中
+ li t3, 3 // 送信中かつ受信済
+ beq t0, t2, putc_wait
+ beq t0, t3, putc_wait
+putc_break:
+ ret
+
+//---------------------------------------------------------
+// だいたい1秒間スリープ
+//---------------------------------------------------------
+sleep:
+ li t0, 0
+sleep_loop:
+ addi t0, t0, 1
+ li t1, 1000000
+ beq t0, t1, sleep_break
+ j sleep_loop
+sleep_break:
+ ret
diff --git a/rtl/sdram.v b/rtl/sdram.v
new file mode 100644
index 0000000..20329f5
--- /dev/null
+++ b/rtl/sdram.v
@@ -0,0 +1,354 @@
+/*
+ * mt48lc16m16a2_ctrl - A sdram controller
+ *
+ * Copyright (C) 2022 Hirosh Dabui <hirosh@dabui.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+default_nettype none timescale 1ns / 1ps
+
+// ===============================
+// 16Mx16 = 32MByte
+// Row addressing 8k (A0-A12)
+// Bank Switching 4 (BA0, BA1)
+// Column Addressing 512 (A0-A8)
+// ===============================
+ parameter SDRAM_CLK_FREQ = 64,
+ parameter TRP_NS = 20,
+ parameter TRC_NS = 66,
+ parameter TRCD_NS = 20,
+ parameter TCH_NS = 2,
+ parameter CAS = 3'd2
+) (
+ input wire clk,
+ input wire resetn,
+
+ input wire valid,
+ output reg ready,
+
+ output wire sdram_clk,
+ output wire sdram_cke,
+ output wire 1:0 sdram_dqm, + output wire 12:0 sdram_addr, // A0-A12 row address, A0-A8 column address + output wire 1:0 sdram_ba, // bank select A11,A12 + output wire sdram_csn,
+ output wire sdram_wen,
+ output wire sdram_rasn,
+ output wire sdram_casn,
+ inout wire 15:0 sdram_dq +);
+
+ localparam ONE_MICROSECOND = SDRAM_CLK_FREQ;
+ localparam WAIT_100US = 100 * ONE_MICROSECOND; // 64 * 1/64e6 = 1us => 100 * 1us
+ // command period; PRE to ACT in ns, e.g. 20ns
+ localparam TRP = $rtoi((TRP_NS * ONE_MICROSECOND / 1000) + 1);
+ // tRC command period (REF to REF/ACT TO ACT) in ns
+ localparam TRC = $rtoi((TRC_NS * ONE_MICROSECOND / 1000) + 1); //
+ // tRCD active command to read/write command delay; row-col-delay in ns
+ localparam TRCD = $rtoi((TRCD_NS * ONE_MICROSECOND / 1000) + 1);
+ // tCH command hold time
+ localparam TCH = $rtoi((TCH_NS * ONE_MICROSECOND / 1000) + 1);
+
+ initial begin
+ $display("Clk frequence: %d MHz", SDRAM_CLK_FREQ);
+ $display("WAIT_100US: %d cycles", WAIT_100US);
+ $display("TRP: %d cycles", TRP);
+ $display("TRC: %d cycles", TRC);
+ $display("TRCD: %d cycles", TRCD);
+ $display("TCH: %d cycles", TCH);
+ $display("CAS_LATENCY: %d cycles", CAS_LATENCY);
+ end
+
+ localparam BURST_LENGTH = 3'b001; // 000=1, 001=2, 010=4, 011=8
+ localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved
+ localparam CAS_LATENCY = CAS; // 2/3 allowed, tRCD=20ns -> 3 cycles@128MHz
+ localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed
+ localparam NO_WRITE_BURST = 1'b0; // 0= write burst enabled, 1=only single access write
+ localparam sdram_mode = {1'b0, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH};
+ //
+ // ISSI-IS425 datasheet page 16
+ // (CS, RAS, CAS, WE)
+ localparam CMD_MRS = 4'b0000; // mode register set
+ localparam CMD_ACT = 4'b0011; // bank active
+ localparam CMD_READ = 4'b0101; // to have read variant with autoprecharge set A10=H
+ localparam CMD_WRITE = 4'b0100; // A10=H to have autoprecharge
+ localparam CMD_BST = 4'b0110; // burst stop
+ localparam CMD_PRE = 4'b0010; // precharge selected bank, A10=H both banks
+ localparam CMD_REF = 4'b0001; // auto refresh (cke=H), selfrefresh assign cke=L
+ localparam CMD_NOP = 4'b0111;
+ localparam CMD_DSEL = 4'b1xxx;
+
+ reg cke;
+ reg cke_nxt;
+
+ assign sdram_clk = clk;
+ assign sdram_cke = cke;
+ assign sdram_addr = saddr;
+ assign sdram_dqm = dqm;
+ assign {sdram_csn, sdram_rasn, sdram_casn, sdram_wen} = command;
+ assign sdram_ba = ba;
+
+ // state machine stuff
+ localparam RESET = 0;
+ localparam ASSERT_CKE = 1;
+ localparam INIT_SEQ_PRE_CHARGE_ALL = 2;
+ localparam INIT_SEQ_AUTO_REFRESH0 = 3;
+ localparam INIT_SEQ_AUTO_REFRESH1 = 4;
+ localparam INIT_SEQ_LOAD_MODE = 5;
+ localparam IDLE = 6;
+ localparam COL_READ = 7;
+ localparam COL_READL = 8;
+ localparam COL_READH = 9;
+ localparam COL_WRITEL = 10;
+ localparam COL_WRITEH = 11;
+ localparam AUTO_REFRESH = 12;
+ localparam PRE_CHARGE_ALL = 13;
+ localparam WAIT_STATE = 14;
+ localparam LAST_STATE = 15;
+
+ localparam STATE_WIDTH = $clog2(LAST_STATE);
+
+ localparam WAIT_STATE_WIDTH = $clog2(WAIT_100US);
+
+ reg ready_nxt;
+
+ reg update_ready;
+ reg update_ready_nxt;
+
+ assign sdram_dq = oe ? dq : 16'hz;
+
+ reg oe;
+ reg oe_nxt;
+
+ always @(posedge clk) begin
+ if (~resetn) begin
+ state <= RESET;
+ ret_state <= RESET;
+ ready <= 1'b0;
+ wait_states <= 0;
+ dout <= 0;
+ command <= CMD_NOP;
+ dqm <= 2'b11;
+ dq <= 0;
+ ba <= 2'b11;
+ oe <= 1'b0;
+ saddr <= 0;
+ update_ready <= 1'b0;
+ end else begin
+ dq <= dq_nxt;
+ dout <= dout_nxt;
+ state <= state_nxt;
+ ready <= ready_nxt;
+ dqm <= dqm_nxt;
+ cke <= cke_nxt;
+ command <= command_nxt;
+ wait_states <= wait_states_nxt;
+ ret_state <= ret_state_nxt;
+ ba <= ba_nxt;
+ oe <= oe_nxt;
+ saddr <= saddr_nxt;
+ update_ready <= update_ready_nxt;
+ end
+ end
+
+ always @(*) begin
+ wait_states_nxt = wait_states;
+ state_nxt = state;
+ ready_nxt = ready;
+ ret_state_nxt = ret_state;
+ dout_nxt = dout;
+ command_nxt = command;
+
+ cke_nxt = cke;
+ saddr_nxt = saddr;
+ ba_nxt = ba;
+ dqm_nxt = dqm;
+ oe_nxt = oe;
+ dq_nxt = dq;
+ update_ready_nxt = update_ready;
+
+ case (state)
+ RESET: begin
+ cke_nxt = 1'b0;
+ wait_states_nxt = WAIT_100US;
+ ret_state_nxt = ASSERT_CKE;
+ state_nxt = WAIT_STATE;
+ end
+
+ ASSERT_CKE: begin
+ cke_nxt = 1'b1;
+ wait_states_nxt = 2;
+ ret_state_nxt = INIT_SEQ_PRE_CHARGE_ALL;
+ state_nxt = WAIT_STATE;
+ end
+
+ INIT_SEQ_PRE_CHARGE_ALL: begin
+ cke_nxt = 1'b1;
+ command_nxt = CMD_PRE;
+ wait_states_nxt = TRP;
+ ret_state_nxt = INIT_SEQ_AUTO_REFRESH0;
+ state_nxt = WAIT_STATE;
+ end
+
+ INIT_SEQ_AUTO_REFRESH0: begin
+ command_nxt = CMD_REF;
+ wait_states_nxt = TRC;
+ ret_state_nxt = INIT_SEQ_AUTO_REFRESH1;
+ state_nxt = WAIT_STATE;
+ end
+
+ INIT_SEQ_AUTO_REFRESH1: begin
+ command_nxt = CMD_REF;
+ wait_states_nxt = TRC;
+ ret_state_nxt = INIT_SEQ_LOAD_MODE;
+ state_nxt = WAIT_STATE;
+ end
+
+ INIT_SEQ_LOAD_MODE: begin
+ command_nxt = CMD_MRS;
+ saddr_nxt = sdram_mode;
+ wait_states_nxt = TCH;
+ ret_state_nxt = IDLE;
+ state_nxt = WAIT_STATE;
+ end
+
+ IDLE: begin
+ oe_nxt = 1'b0;
+ dqm_nxt = 2'b11;
+ ready_nxt = 1'b0;
+ if (valid && !ready) begin
+ command_nxt = CMD_ACT;
+ wait_states_nxt = TRCD;
+ ret_state_nxt = |wmask ? COL_WRITEL : COL_READ;
+ update_ready_nxt = 1'b1;
+ state_nxt = WAIT_STATE;
+ end else begin
+ /* autorefresh */
+ command_nxt = CMD_REF;
+ saddr_nxt = 0;
+ ba_nxt = 0;
+ wait_states_nxt = 3; //TRC;
+ ret_state_nxt = IDLE;
+ update_ready_nxt = 1'b0;
+ state_nxt = WAIT_STATE;
+ end
+ end
+
+ COL_READ: begin
+ command_nxt = CMD_READ;
+ dqm_nxt = 2'b00;
+ saddr_nxt = {3'b001, addr10:2, 1'b0}; // autoprecharge and column + wait_states_nxt = CAS_LATENCY;
+ ret_state_nxt = COL_READL;
+ state_nxt = WAIT_STATE;
+ end
+
+ COL_READL: begin
+ command_nxt = CMD_NOP;
+ dqm_nxt = 2'b00;
+ dout_nxt15:0 = sdram_dq; + //wait_states_nxt = TRP;
+ // ret_state_nxt = COL_READH;
+ state_nxt = COL_READH;
+ end
+
+ COL_READH: begin
+ command_nxt = CMD_NOP;
+ dqm_nxt = 2'b00;
+ dout_nxt31:16 = sdram_dq; + wait_states_nxt = TRP;
+ update_ready_nxt = 1'b1;
+ ret_state_nxt = IDLE;
+ state_nxt = WAIT_STATE;
+ end
+
+ COL_WRITEL: begin
+ command_nxt = CMD_WRITE;
+ saddr_nxt = {3'b001, addr10:2, 1'b0}; // autoprecharge and column + oe_nxt = 1'b1;
+ //wait_states_nxt = TRP;
+ //ret_state_nxt = COL_WRITEH;
+ state_nxt = COL_WRITEH;
+ end
+
+ COL_WRITEH: begin
+ command_nxt = CMD_NOP;
+ saddr_nxt = {3'b001, addr10:2, 1'b0}; // autoprecharge and column + oe_nxt = 1'b1;
+ wait_states_nxt = TRP;
+ update_ready_nxt = 1'b1;
+ ret_state_nxt = IDLE;
+ state_nxt = WAIT_STATE;
+ end
+
+ PRE_CHARGE_ALL: begin
+ command_nxt = CMD_PRE;
+ saddr_nxt10 = 1'b1; // select all banks + ba_nxt = 0;
+ wait_states_nxt = TRP;
+ ret_state_nxt = IDLE;
+ state_nxt = WAIT_STATE;
+ end
+
+ WAIT_STATE: begin
+ command_nxt = CMD_NOP;
+ wait_states_nxt = wait_states - 1;
+ if (wait_states == 1) begin
+ state_nxt = ret_state;
+ if (ret_state == IDLE && update_ready) begin
+ update_ready_nxt = 1'b0;
+ ready_nxt = 1'b1;
+ end
+ end
+ end
+
+ default: begin
+ state_nxt = state;
+ end
+ endcase
+ end
+
+endmodule
diff --git a/rtl/ulx3s_top.sv b/rtl/ulx3s_top.sv
index 6c020ec..5f9cd12 100644
--- a/rtl/ulx3s_top.sv
+++ b/rtl/ulx3s_top.sv
@@ -5,10 +5,35 @@ module ulx3s_top(
input wire clk_25mhz,
+ // UART
output wire ftdi_rxd, // FPGA transmits to ftdi
- input wire ftdi_txd // FPGA receives from ftdi
+ input wire ftdi_txd, // FPGA receives from ftdi
+ // SDRAM
+ output sdram_cs_n,
+ output sdram_cke,
+ output sdram_ras_n,
+ output sdram_cas_n,
+ output sdram_we_n,
+ output sdram_clock
);
+ localparam SYSCLK = 25_000_000;
+
+ //------------------------------------------------------------------
+ // 外部信号線との接続
+ //------------------------------------------------------------------
+ assign clk = clk_25mhz;
+ assign reset_n = btn0; // btn0 は押すとデアサートされる +
+ assign led = led_ctl_mem_rdata7:0; + // assign led = peek7:0; + // assign led = uart_ctl_mem_rdata;
+
+
//------------------------------------------------------------------
// CPU
//------------------------------------------------------------------
@@ -173,40 +198,67 @@ module ulx3s_top(
end
+ //------------------------------------------------------------------
+ // SDRAM コントローラ
+ //------------------------------------------------------------------
+
+ .SDRAM_CLK_FREQ(SYSCLK / 1_000_000)
+ ) sdram_inst (
+ .clk(clk),
+ .resetn(reset_n),
+ .addr(sdram_mem_addr),
+ .din(mem_wdata),
+ .dout(sdram_mem_rdata),
+ .wmask(mem_wstrb),
+ .ready(sdram_mem_ready),
+ .sdram_clk(sdram_clock),
+ .sdram_cke(sdram_cke),
+ .sdram_csn(sdram_cs_n),
+ .sdram_rasn(sdram_ras_n),
+ .sdram_casn(sdram_cas_n),
+ .sdram_wen(sdram_we_n),
+ .sdram_addr(sdram_a),
+ .sdram_ba(sdram_ba),
+ .sdram_dq(sdram_dq),
+ .sdram_dqm(sdram_dm),
+ .valid(sdram_valid)
+ );
+
+ logic sdram_valid;
+ logic sdram_mem_ready;
+ logic 31:0 sdram_mem_rdata; + logic 24:0 sdram_mem_addr; +
+ assign sdram_mem_addr = { (mem_addr & 32'h0fff_ffff) >> 2, 2'b00 };
+ assign sdram_valid = sdram_en && mem_valid;
+
//------------------------------------------------------------------
// 周辺機器との接続
//------------------------------------------------------------------
// メモリマップ
assign bram_en = (mem_addr < 8192) ? 1'b1 : 1'b0;
+ assign sdram_en = ((mem_addr & 32'hf000_0000) == 32'h4000_0000) ? 1'b1 : 1'b0;
assign uart_data_en = (mem_addr == 32'hf0000000) ? 1'b1 : 1'b0;
assign uart_ctl_en = (mem_addr == 32'hf0000004) ? 1'b1 : 1'b0;
assign led_ctl_en = (mem_addr == 32'hf0001000) ? 1'b1 : 1'b0;
// 周辺機器 => CPU
assign mem_ready = (bram_en) ? bram_mem_ready :
+ (sdram_en) ? sdram_mem_ready :
(led_ctl_en) ? led_ctl_mem_ready :
(uart_data_en) ? uart_data_mem_ready :
(uart_ctl_en) ? uart_ctl_mem_ready
: 1'b1; // 接続先のペリフェラルが存在しない場合は常に ready = 1 とする
assign mem_rdata = (bram_en) ? bram_mem_rdata :
+ (sdram_en) ? sdram_mem_rdata :
(led_ctl_en) ? led_ctl_mem_rdata :
(uart_data_en) ? uart_data_mem_rdata :
(uart_ctl_en) ? uart_ctl_mem_rdata
: 32'h0;
-
- //------------------------------------------------------------------
- // 外部信号線との接続
- //------------------------------------------------------------------
- assign clk = clk_25mhz;
- assign reset_n = btn0; // btn0 は押すとデアサートされる -
- assign led = led_ctl_mem_rdata7:0; - // assign led = peek7:0; - // assign led = uart_ctl_mem_rdata;
-
endmodule
// LED コントローラを雑に実装
diff --git a/rtl/ulx3s_v20.lpf b/rtl/ulx3s_v20.lpf
index 49d246e..88e5282 100644
--- a/rtl/ulx3s_v20.lpf
+++ b/rtl/ulx3s_v20.lpf
@@ -236,84 +236,84 @@ IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; ## SDRAM "ram" sheet
-LOCATE COMP "sdram_clk" SITE "F19";
+LOCATE COMP "sdram_clock" SITE "F19";
+IOBUF PORT "sdram_clock" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
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_a0" SITE "M20"; -LOCATE COMP "sdram_a1" SITE "M19"; -LOCATE COMP "sdram_a2" SITE "L20"; -LOCATE COMP "sdram_a3" SITE "L19"; -LOCATE COMP "sdram_a4" SITE "K20"; -LOCATE COMP "sdram_a5" SITE "K19"; -LOCATE COMP "sdram_a6" SITE "K18"; -LOCATE COMP "sdram_a7" SITE "J20"; -LOCATE COMP "sdram_a8" SITE "J19"; -LOCATE COMP "sdram_a9" SITE "H20"; -LOCATE COMP "sdram_a10" SITE "N19"; -LOCATE COMP "sdram_a11" SITE "G20"; -LOCATE COMP "sdram_a12" SITE "G19"; -LOCATE COMP "sdram_ba0" SITE "P19"; -LOCATE COMP "sdram_ba1" SITE "N20"; -LOCATE COMP "sdram_dqm0" SITE "U19"; -LOCATE COMP "sdram_dqm1" SITE "E20"; -LOCATE COMP "sdram_d0" SITE "J16"; -LOCATE COMP "sdram_d1" SITE "L18"; -LOCATE COMP "sdram_d2" SITE "M18"; -LOCATE COMP "sdram_d3" SITE "N18"; -LOCATE COMP "sdram_d4" SITE "P18"; -LOCATE COMP "sdram_d5" SITE "T18"; -LOCATE COMP "sdram_d6" SITE "T17"; -LOCATE COMP "sdram_d7" SITE "U20"; -LOCATE COMP "sdram_d8" SITE "E19"; -LOCATE COMP "sdram_d9" SITE "D20"; -LOCATE COMP "sdram_d10" SITE "D19"; -LOCATE COMP "sdram_d11" SITE "C20"; -LOCATE COMP "sdram_d12" SITE "E18"; -LOCATE COMP "sdram_d13" SITE "F18"; -LOCATE COMP "sdram_d14" SITE "J18"; -LOCATE COMP "sdram_d15" 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;
+LOCATE COMP "sdram_cs_n" SITE "P20";
+IOBUF PORT "sdram_cs_n" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "sdram_ras_n" SITE "R20";
+IOBUF PORT "sdram_ras_n" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "sdram_cas_n" SITE "T19";
+IOBUF PORT "sdram_cas_n" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "sdram_we_n" SITE "T20";
+IOBUF PORT "sdram_we_n" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
+LOCATE COMP "sdram_a0" SITE "M20"; IOBUF PORT "sdram_a0" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a1" SITE "M19"; IOBUF PORT "sdram_a1" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a2" SITE "L20"; IOBUF PORT "sdram_a2" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a3" SITE "L19"; IOBUF PORT "sdram_a3" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a4" SITE "K20"; IOBUF PORT "sdram_a4" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a5" SITE "K19"; IOBUF PORT "sdram_a5" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a6" SITE "K18"; IOBUF PORT "sdram_a6" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a7" SITE "J20"; IOBUF PORT "sdram_a7" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a8" SITE "J19"; IOBUF PORT "sdram_a8" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a9" SITE "H20"; IOBUF PORT "sdram_a9" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a10" SITE "N19"; IOBUF PORT "sdram_a10" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a11" SITE "G20"; IOBUF PORT "sdram_a11" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_a12" SITE "G19"; IOBUF PORT "sdram_a12" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_ba0" SITE "P19"; IOBUF PORT "sdram_ba0" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_ba1" SITE "N20"; IOBUF PORT "sdram_ba1" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_dqm0" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_dqm1" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d0" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d1" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d2" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d3" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d4" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d5" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d6" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d7" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d8" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d9" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d10" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d11" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d12" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d13" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d14" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; -IOBUF PORT "sdram_d15" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dm0" SITE "U19"; +IOBUF PORT "sdram_dm0" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dm1" SITE "E20"; +IOBUF PORT "sdram_dm1" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq0" SITE "J16"; +IOBUF PORT "sdram_dq0" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq1" SITE "L18"; +IOBUF PORT "sdram_dq1" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq2" SITE "M18"; +IOBUF PORT "sdram_dq2" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq3" SITE "N18"; +IOBUF PORT "sdram_dq3" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq4" SITE "P18"; +IOBUF PORT "sdram_dq4" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq5" SITE "T18"; +IOBUF PORT "sdram_dq5" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq6" SITE "T17"; +IOBUF PORT "sdram_dq6" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq7" SITE "U20"; +IOBUF PORT "sdram_dq7" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq8" SITE "E19"; +IOBUF PORT "sdram_dq8" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq9" SITE "D20"; +IOBUF PORT "sdram_dq9" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq10" SITE "D19"; +IOBUF PORT "sdram_dq10" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq11" SITE "C20"; +IOBUF PORT "sdram_dq11" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq12" SITE "E18"; +IOBUF PORT "sdram_dq12" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq13" SITE "F18"; +IOBUF PORT "sdram_dq13" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq14" SITE "J18"; +IOBUF PORT "sdram_dq14" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sdram_dq15" SITE "J17"; +IOBUF PORT "sdram_dq15" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # GPDI differential interface (Video) "gpdi" sheet
LOCATE COMP "gpdi_dp0" SITE "A16"; # Blue +