Update sys. Re-organize the sources.

This commit is contained in:
sorgelig
2020-05-11 23:17:53 +08:00
parent 0c1cb37dba
commit 5a66d5ec1c
102 changed files with 1996 additions and 1364 deletions

233
rtl/memory/arbiter.v Normal file
View File

@ -0,0 +1,233 @@
// PentEvo project (c) NedoPC 2008-2011
//
// DRAM arbiter. Shares DRAM between CPU, video data fetcher and other devices
//
// Arbitration is made on full 8-cycle access blocks. Each cycle is defined by dram.v and consists of 4 fpga clocks.
// During each access block, there can be either no videodata access, 1 videodata access, 2, 4 or 8 accesses.
// All spare cycles can be used by CPU or other devices. If no device uses memory in the given cycle, refresh cycle is performed.
//
// In each access block, videodata accesses are spreaded all over the block so that CPU receives cycle
// as fast as possible, until there is absolute need to fetch remaining video data.
//
// Examples:
//
// | access block | 4 video accesses during block, no processor accesses. video accesses are done
// | vid | vid | vid | vid | ref | ref | ref | ref | as soon as possible, spare cycles are refresh ones
//
// | access block | 4 video accesses during block, processor requests access every other cycle
// | vid | prc | vid | prc | vid | prc | vid | prc |
//
// | access block | 4 video accesses, processor begins requesting cycles continously from second one
// | vid | prc | prc | prc | prc | vid | vid | vid | so it is given cycles while there is such possibility. after that processor
// can't access mem until the end of access block and stalls
//
// | access block | 8 video accesses, processor stalls, if it is requesting cycles
// | vid | vid | vid | vid | vid | vid | vid | vid |
//
// | access block | 2 video accesses, single processor request, other cycles are refresh ones
// | vid | vid | ref | ref | cpu | ref | ref | ref |
//
// | access block | 4 video accesses, single processor request, other cycles are refresh ones
// | vid | vid | cpu | vid | vid | ref | ref | ref |
//
// access block begins at any dram cycle, then blocks go back-to-back
//
// key signals are go and XXX_req, sampled at the end of each dram cycle. Must be set to the module at c3 clock cycle.
// CPU can have either normal or lower access priority to the DRAM.
// At the INT active (32 of 3.5MHz clocks) the priority is raised to normal, so that CPU won't miss its interrupt.
// This should be considered if dummy RAM access used for waiting for the end of DMA operation instead of status bit polling.
//
// DRAM access priority:
// Z80 normal Z80 low
// - VIDEO - VIDEO
// - CPU - TS
// - TM - TM
// - TS - DMA
// - DMA - CPU
module arbiter
(
input clk,
input c0,
input c1,
input c2,
input c3,
// dram.v interface
output [20:0] dram_addr, // address for dram access
output dram_req, // dram request
output dram_rnw, // Read-NotWrite
output [ 1:0] dram_bsel, // byte select: bsel[1] for wrdata[15:8], bsel[0] for wrdata[7:0]
output [15:0] dram_wrdata, // data to be written
// video
input [20:0] video_addr, // during access block, only when video_strobe==1
input go, // start video access blocks
input [ 4:0] video_bw, // [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
// [2:0] - need cycles
output video_pre_next, // (c1)
output video_next, // (c2) at this signal video_addr may be changed; it is one clock leading the video_strobe
output video_strobe, // (c3) one-cycle strobe meaning that video_data is available
output video_next_strobe, // (c3) one-cycle strobe meaning that video_data is available
output next_vid, // used for TM prefetch
// CPU
input [20:0] cpu_addr,
input [ 7:0] cpu_wrdata,
input cpu_req,
input cpu_rnw,
input cpu_wrbsel,
output reg cpu_next, // next cycle is allowed to be used by CPU
output reg cpu_strobe, // c2 strobe
output reg cpu_latch, // c2-c3 strobe
output curr_cpu_o,
// DMA
input [20:0] dma_addr,
input [15:0] dma_wrdata,
input dma_req,
input dma_rnw,
output dma_next,
// TS
input [20:0] ts_addr,
input ts_req,
output ts_pre_next,
output ts_next,
// TM
input [20:0] tm_addr,
input tm_req,
output tm_next
);
assign curr_cpu_o = curr_cpu;
localparam CYCLES = 5;
localparam CYC_CPU = 5'b00001;
localparam CYC_VID = 5'b00010;
localparam CYC_TS = 5'b00100;
localparam CYC_TM = 5'b01000;
localparam CYC_DMA = 5'b10000;
localparam CYC_FREE = 5'b00000;
localparam CPU = 0;
localparam VIDEO = 1;
localparam TS = 2;
localparam TM = 3;
localparam DMA = 4;
reg [CYCLES-1:0] curr_cycle; // type of the cycle in progress
reg [CYCLES-1:0] next_cycle; // type of the next cycle
wire next_cpu = next_cycle[CPU];
assign next_vid = next_cycle[VIDEO];
wire next_ts = next_cycle[TS];
wire next_tm = next_cycle[TM];
wire next_dma = next_cycle[DMA];
wire curr_cpu = curr_cycle[CPU];
wire curr_vid = curr_cycle[VIDEO];
wire curr_ts = curr_cycle[TS];
wire curr_tm = curr_cycle[TM];
wire curr_dma = curr_cycle[DMA];
// track blk_rem counter:
// how many cycles left to the end of block (7..0)
wire [2:0] blk_nrem = (video_start && go) ? {video_bw[4:3], 1'b1} : (video_start ? 3'd0 : (blk_rem - 3'd1));
wire bw_full = ~|{video_bw[4] & video_bw[2], video_bw[3] & video_bw[1], video_bw[0]}; // stall when 000/00/0
wire video_start = ~|blk_rem;
wire video_only = stall || (vid_rem == blk_rem);
wire video_idle = ~|vid_rem;
reg [2:0] blk_rem; // remaining accesses in a block (7..0)
reg stall;
always @(posedge clk) begin
if (c3) begin
blk_rem <= blk_nrem;
if (video_start) stall <= bw_full & go;
end
end
// track vid_rem counter
// how many video cycles left to the end of block (7..0)
wire [2:0] vid_nrem = (go && video_start) ? vid_nrem_start : (next_vid ? vid_nrem_next : vid_rem);
wire [2:0] vid_nrem_start = (cpu_req && !dev_over_cpu) ? vidmax : (vidmax - 3'd1);
wire [2:0] vid_nrem_next = video_idle ? 3'd0 : (vid_rem - 3'd1);
wire [2:0] vidmax = {video_bw[2:0]}; // number of cycles for video access
reg [2:0] vid_rem; // remaining video accesses in block
always @(posedge clk) if (c3) vid_rem <= vid_nrem;
// next cycle decision
wire [CYCLES-1:0] cyc_dev = tm_req ? CYC_TM : (ts_req ? CYC_TS : CYC_DMA);
wire dev_req = ts_req || tm_req || dma_req;
// wire dev_over_cpu = (((ts_req || tm_req) && ts_z80_lp) || (dma_req && dma_z80_lp)) && int_n; // CPU gets higher priority to acknowledge the INT
wire dev_over_cpu = 0;
always @* begin
if (video_start) begin // video burst start
if (go) begin // video active line - 38us-ON, 26us-ON
cpu_next = dev_over_cpu ? 1'b0 : !bw_full;
next_cycle = dev_over_cpu ? CYC_VID : (bw_full ? CYC_VID : (cpu_req ? CYC_CPU : CYC_VID));
end
else begin // video idle
cpu_next = !dev_over_cpu;
next_cycle = dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (dev_req ? cyc_dev : CYC_FREE));
end
end
else begin // video burst in progress
cpu_next = dev_over_cpu ? 1'b0 : !video_only;
next_cycle = video_only ? CYC_VID : (dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (!video_idle ? CYC_VID : (dev_req ? cyc_dev : CYC_FREE))));
end
end
always @(posedge clk) if (c3) curr_cycle <= next_cycle;
// DRAM interface
assign dram_wrdata= curr_dma ? dma_wrdata : {cpu_wrdata,cpu_wrdata}; // write data has to be clocked at c0 in dram.v
assign dram_bsel = {cpu_wrbsel | next_dma, ~cpu_wrbsel | next_dma};
assign dram_req = |next_cycle;
assign dram_rnw = next_cpu ? cpu_rnw : ~next_dma | dma_rnw;
assign dram_addr = {21{next_cpu}} & cpu_addr
| {21{next_vid}} & video_addr
| {21{next_ts }} & ts_addr
| {21{next_tm }} & tm_addr
| {21{next_dma}} & dma_addr;
reg cpu_rnw_r;
always @(posedge clk) if (c3) cpu_rnw_r <= cpu_rnw;
// generation of read strobes: for video and cpu
always @(posedge clk) begin
if (c1) begin
cpu_strobe <= curr_cpu && cpu_rnw_r;
cpu_latch <= curr_cpu && cpu_rnw_r;
end
else if (c2) cpu_strobe <= 1'b0;
else if (c3) cpu_latch <= 1'b0;
end
assign video_pre_next = curr_vid & c1;
assign video_next = curr_vid & c2;
assign video_strobe = curr_vid && c3;
assign video_next_strobe = next_vid && c3;
assign ts_pre_next = curr_ts & c1;
assign ts_next = curr_ts & c2;
assign tm_next = curr_tm & c2;
assign dma_next = curr_dma & c2;
endmodule

124
rtl/memory/ddram.sv Normal file
View File

@ -0,0 +1,124 @@
//
// ddram.v
//
// DE10-nano DDR3 memory interface
//
// Copyright (c) 2017 Sorgelig
//
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ------------------------------------------
//
// 8-bit version
module ddram
(
input reset,
input DDRAM_CLK,
input DDRAM_BUSY,
output [7:0] DDRAM_BURSTCNT,
output [28:0] DDRAM_ADDR,
input [63:0] DDRAM_DOUT,
input DDRAM_DOUT_READY,
output DDRAM_RD,
output [63:0] DDRAM_DIN,
output [7:0] DDRAM_BE,
output DDRAM_WE,
input [27:0] addr, // 256MB at the end of 1GB
output [7:0] dout, // data output to cpu
input [7:0] din, // data input from cpu
input we, // cpu requests write
input rd, // cpu requests read
output ready // dout is valid. Ready to accept new read/write.
);
assign DDRAM_BURSTCNT = 1;
assign DDRAM_BE = (8'd1<<ram_address[2:0]) | {8{ram_read}};
assign DDRAM_ADDR = {4'b0011, ram_address[27:3]}; // RAM at 0x30000000
assign DDRAM_RD = ram_read;
assign DDRAM_DIN = ram_cache;
assign DDRAM_WE = ram_write;
assign dout = ram_q;
assign ready = ~busy;
reg [7:0] ram_q;
reg [27:0] ram_address;
reg ram_read;
reg [63:0] ram_cache;
reg ram_write;
reg [7:0] cached;
reg busy;
always @(posedge DDRAM_CLK)
begin
reg old_rd, old_we;
reg old_reset;
reg state;
old_reset <= reset;
if(old_reset && ~reset) begin
busy <= 0;
state <= 0;
cached <= 0;
end
if(!DDRAM_BUSY)
begin
ram_write <= 0;
ram_read <= 0;
if(state) begin
if(DDRAM_DOUT_READY) begin
ram_q <= DDRAM_DOUT[{ram_address[2:0], 3'b000} +:8];
ram_cache <= DDRAM_DOUT;
cached <= 8'hFF;
state <= 0;
busy <= 0;
end
end
else begin
old_rd <= rd;
old_we <= we;
busy <= 0;
if(~old_we && we) begin
ram_cache[{addr[2:0], 3'b000} +:8] <= din;
ram_address <= addr;
busy <= 1;
ram_write <= 1;
cached <= ((ram_address[27:3] == addr[27:3]) ? cached : 8'h00) | (8'd1<<addr[2:0]);
end
if(~old_rd && rd) begin
if((ram_address[27:3] == addr[27:3]) && (cached & (8'd1<<addr[2:0]))) begin
ram_q <= ram_cache[{addr[2:0], 3'b000} +:8];
end
else begin
ram_address <= addr;
ram_read <= 1;
state <= 1;
cached <= 0;
busy <= 1;
end
end
end
end
end
endmodule

337
rtl/memory/dma.v Normal file
View File

@ -0,0 +1,337 @@
// This module serves direct DRAM-to-device data transfer
// to do
// - probably add the extra 8 bit counter for number of bursts
module dma
(
// clocks
input wire clk,
input wire c2,
input wire reset,
// interface
input wire [8:0] dmaport_wr,
output wire dma_act,
output reg [15:0] data,
output wire [ 7:0] wraddr,
output wire int_start,
// Z80
input wire [7:0] zdata,
// DRAM interface
output wire [20:0] dram_addr,
input wire [15:0] dram_rddata,
output wire [15:0] dram_wrdata,
output wire dram_req,
output wire dram_rnw,
input wire dram_next,
// SPI interface
input wire [7:0] spi_rddata,
output wire [7:0] spi_wrdata,
output wire spi_req,
input wire spi_stb,
// IDE interface
input wire [15:0] ide_in,
output wire [15:0] ide_out,
output wire ide_req,
output wire ide_rnw,
input wire ide_stb,
// CRAM interface
output wire cram_we,
// SFILE interface
output wire sfile_we
);
// mode:
// 0 - device to RAM (read from device)
// 1 - RAM to device (write to device)
assign wraddr = d_addr[7:0];
wire dma_saddrl = dmaport_wr[0];
wire dma_saddrh = dmaport_wr[1];
wire dma_saddrx = dmaport_wr[2];
wire dma_daddrl = dmaport_wr[3];
wire dma_daddrh = dmaport_wr[4];
wire dma_daddrx = dmaport_wr[5];
wire dma_len = dmaport_wr[6];
wire dma_launch = dmaport_wr[7];
wire dma_num = dmaport_wr[8];
// DRAM
assign dram_addr = state_rd ? ((!dv_blt || !phase_blt) ? s_addr : d_addr) : d_addr;
assign dram_wrdata = data;
assign dram_req = dma_act && state_mem;
assign dram_rnw = state_rd;
// devices
localparam DEV_RAM = 3'b0001;
localparam DEV_BLT1 = 4'b1001;
localparam DEV_BLT2 = 4'b0110;
localparam DEV_FIL = 4'b0100;
localparam DEV_SPI = 3'b010;
localparam DEV_IDE = 3'b011;
localparam DEV_CRM = 4'b1100;
localparam DEV_SFL = 4'b1101;
localparam DEV_FDD = 4'b0101;
wire [2:0] dev_bid = device[2:0]; // bidirectional
wire [3:0] dev_uni = device[3:0]; // unidirectional
wire dma_wnr = device[3]; // 0 - device to RAM / 1 - RAM to device
wire dv_ram = (dev_uni == DEV_RAM) || (dev_uni == DEV_BLT1) || (dev_uni == DEV_BLT2) || (dev_uni == DEV_FIL);
wire dv_blt = (dev_uni == DEV_BLT1) || (dev_uni == DEV_BLT2);
wire dv_fil = (dev_uni == DEV_FIL);
wire dv_spi = (dev_bid == DEV_SPI);
wire dv_ide = (dev_bid == DEV_IDE);
wire dv_crm = (dev_uni == DEV_CRM);
wire dv_sfl = (dev_uni == DEV_SFL);
wire dev_req = dma_act && state_dev;
wire dev_stb = cram_we || sfile_we || ide_int_stb || (spi_int_stb && bsel && dma_act);
assign cram_we = dev_req && dv_crm && state_wr;
assign sfile_we = dev_req && dv_sfl && state_wr;
// SPI
wire spi_int_stb = dv_spi && spi_stb;
assign spi_wrdata = {8{state_rd}} | (bsel ? data[15:8] : data[7:0]); // send FF on read cycles
assign spi_req = dev_req && dv_spi;
// IDE
wire ide_int_stb = dv_ide && ide_stb;
assign ide_out = data;
assign ide_req = dev_req && dv_ide;
assign ide_rnw = state_rd;
// blitter
wire [15:0] blt_rddata = (dev_uni == DEV_BLT1) ? blt1_rddata : blt2_rddata;
// Mode 1
wire [15:0] blt1_rddata = {blt1_data_h, blt1_data_l};
wire [7:0] blt1_data_h = dma_asz ? blt1_data32 : {blt1_data3, blt1_data2};
wire [7:0] blt1_data_l = dma_asz ? blt1_data10 : {blt1_data1, blt1_data0};
wire [7:0] blt1_data32 = |data[15:8] ? data[15:8] : dram_rddata[15:8];
wire [7:0] blt1_data10 = |data[7:0] ? data[7:0] : dram_rddata[7:0];
wire [3:0] blt1_data3 = |data[15:12] ? data[15:12] : dram_rddata[15:12];
wire [3:0] blt1_data2 = |data[11:8] ? data[11:8] : dram_rddata[11:8];
wire [3:0] blt1_data1 = |data[7:4] ? data[7:4] : dram_rddata[7:4];
wire [3:0] blt1_data0 = |data[3:0] ? data[3:0] : dram_rddata[3:0];
// Mode 2
wire [15:0] blt2_rddata = {blt2_data_1, blt2_data_0};
wire [7:0] blt2_data_1 = dma_asz ? blt2_8_data1 : {blt2_4_data3, blt2_4_data2};
wire [7:0] blt2_data_0 = dma_asz ? blt2_8_data0 : {blt2_4_data1, blt2_4_data0};
localparam msk = 8'd255;
wire [8:0] sum80 = data[7:0] + dram_rddata[7:0];
wire [8:0] sum81 = data[15:8] + dram_rddata[15:8];
wire [4:0] sum40 = data[3:0] + dram_rddata[3:0];
wire [4:0] sum41 = data[7:4] + dram_rddata[7:4];
wire [4:0] sum42 = data[11:8] + dram_rddata[11:8];
wire [4:0] sum43 = data[15:12] + dram_rddata[15:12];
wire [7:0] blt2_8_data0 = ((sum80 > msk) && dma_opt) ? msk : sum80[7:0];
wire [7:0] blt2_8_data1 = ((sum81 > msk) && dma_opt) ? msk : sum81[7:0];
wire [3:0] blt2_4_data0 = ((sum40 > msk[3:0]) && dma_opt) ? msk[3:0] : sum40[3:0];
wire [3:0] blt2_4_data1 = ((sum41 > msk[3:0]) && dma_opt) ? msk[3:0] : sum41[3:0];
wire [3:0] blt2_4_data2 = ((sum42 > msk[3:0]) && dma_opt) ? msk[3:0] : sum42[3:0];
wire [3:0] blt2_4_data3 = ((sum43 > msk[3:0]) && dma_opt) ? msk[3:0] : sum43[3:0];
// data aquiring
always @(posedge clk)
if (state_rd)
begin
if (dram_next)
data <= (dv_blt && phase_blt) ? blt_rddata : dram_rddata;
if (ide_int_stb)
data <= ide_in;
if (spi_int_stb)
begin
if (bsel)
data[15:8] <= spi_rddata;
else
data[7:0] <= spi_rddata;
end
end
// states
wire state_rd = ~phase;
wire state_wr = phase;
wire state_dev = !dv_ram && (dma_wnr ^ !phase);
wire state_mem = dv_ram || (dma_wnr ^ phase);
// states processing
wire phase_end = phase_end_ram || phase_end_dev;
wire phase_end_ram = state_mem && dram_next && !blt_hook;
wire phase_end_dev = state_dev && dev_stb;
wire blt_hook = dv_blt && !phase_blt && !phase;
wire fil_hook = dv_fil && phase;
wire phase_blt_end = state_mem && dram_next && !phase;
// blitter cycles:
// phase phase_blt blt_hook activity
// 0 0 1 read src
// 0 1 0 read dst
// 1 1 0 write dst
reg [3:0] device;
reg dma_salgn;
reg dma_dalgn;
reg dma_asz;
reg phase; // 0 - read / 1 - write
reg phase_blt; // 0 - source / 1 - destination
reg bsel; // 0 - lsb / 1 - msb
reg dma_opt;
always @(posedge clk)
if (dma_launch) // write to DMACtrl - launch of DMA burst
begin
dma_opt <= zdata[6];
dma_salgn <= zdata[5];
dma_dalgn <= zdata[4];
dma_asz <= zdata[3];
device <= {zdata[7], zdata[2:0]};
phase <= 1'b0;
phase_blt <= 1'b0;
bsel <= 1'b0;
end
else
begin
if (phase_end && !fil_hook)
phase <= ~phase;
if (phase_blt_end)
phase_blt <= ~phase_blt;
if (spi_int_stb)
bsel <= ~bsel;
end
// counter processing
reg [7:0] b_len; // length of burst
reg [7:0] b_num; // number of bursts
reg [8:0] n_ctr; // counter for bursts
wire [8:0] n_ctr_dec = n_ctr - next_burst;
assign dma_act = !n_ctr[8];
reg [7:0] b_ctr; // counter for cycles in burst
wire [7:0] b_ctr_next = next_burst ? b_len : b_ctr_dec[7:0];
wire [8:0] b_ctr_dec = {1'b0, b_ctr[7:0]} - 9'b1;
wire next_burst = b_ctr_dec[8];
always @(posedge clk)
if (reset)
n_ctr[8] <= 1'b1;
else if (dma_launch)
begin
b_ctr <= b_len;
n_ctr <= {1'b0, b_num};
end
else if (phase && phase_end) // cycle processed
begin
b_ctr <= b_ctr_next;
n_ctr <= n_ctr_dec;
end
// loading of burst parameters
always @(posedge clk)
begin
if (dma_len)
b_len <= zdata;
if (dma_num)
b_num <= zdata;
end
// address processing
// source
wire [20:0] s_addr_next = {s_addr_next_h[13:1], s_addr_next_m, s_addr_next_l[6:0]};
wire [13:0] s_addr_next_h = s_addr[20:7] + s_addr_add_h;
wire [1:0] s_addr_add_h = dma_salgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {s_addr_inc_l[8], 1'b0};
wire s_addr_next_m = dma_salgn ? (dma_asz ? s_addr_next_l[7] : s_addr_next_h[0]) : s_addr_inc_l[7];
wire [7:0] s_addr_next_l = (dma_salgn && next_burst) ? s_addr_r : s_addr_inc_l[7:0];
wire [8:0] s_addr_inc_l = {1'b0, s_addr[7:0]} + 9'b1;
reg [20:0] s_addr; // current source address
reg [7:0] s_addr_r; // source lower address
always @(posedge clk)
if ((dram_next || dev_stb) && state_rd && (!dv_blt || !phase_blt)) // increment RAM source addr
s_addr <= s_addr_next;
else
begin
if (dma_saddrl)
begin
s_addr[6:0] <= zdata[7:1];
s_addr_r[6:0] <= zdata[7:1];
end
if (dma_saddrh)
begin
s_addr[12:7] <= zdata[5:0];
s_addr_r[7] <= zdata[0];
end
if (dma_saddrx)
s_addr[20:13] <= zdata;
end
// destination
wire [20:0] d_addr_next = {d_addr_next_h[13:1], d_addr_next_m, d_addr_next_l[6:0]};
wire [13:0] d_addr_next_h = d_addr[20:7] + d_addr_add_h;
wire [1:0] d_addr_add_h = dma_dalgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {d_addr_inc_l[8], 1'b0};
wire d_addr_next_m = dma_dalgn ? (dma_asz ? d_addr_next_l[7] : d_addr_next_h[0]) : d_addr_inc_l[7];
wire [7:0] d_addr_next_l = (dma_dalgn && next_burst) ? d_addr_r : d_addr_inc_l[7:0];
wire [8:0] d_addr_inc_l = {1'b0, d_addr[7:0]} + 9'b1;
reg [20:0] d_addr; // current dest address
reg [7:0] d_addr_r; // dest lower address
always @(posedge clk)
if ((dram_next || dev_stb) && state_wr) // increment RAM dest addr
d_addr <= d_addr_next;
else
begin
if (dma_daddrl)
begin
d_addr[6:0] <= zdata[7:1];
d_addr_r[6:0] <= zdata[7:1];
end
if (dma_daddrh)
begin
d_addr[12:7] <= zdata[5:0];
d_addr_r[7] <= zdata[0];
end
if (dma_daddrx)
d_addr[20:13] <= zdata;
end
// INT generation
reg dma_act_r;
always @(posedge clk)
dma_act_r <= dma_act && ~reset;
assign int_start = !dma_act && dma_act_r;
endmodule

72
rtl/memory/dpram.v Normal file
View File

@ -0,0 +1,72 @@
module dpram #(parameter DATAWIDTH=8, ADDRWIDTH=8, NUMWORDS=1<<ADDRWIDTH, MEM_INIT_FILE="")
(
input clock,
input [ADDRWIDTH-1:0] address_a,
input [DATAWIDTH-1:0] data_a,
input wren_a,
output [DATAWIDTH-1:0] q_a,
input [ADDRWIDTH-1:0] address_b,
input [DATAWIDTH-1:0] data_b,
input wren_b,
output [DATAWIDTH-1:0] q_b
);
altsyncram altsyncram_component (
.address_a (address_a),
.address_b (address_b),
.clock0 (clock),
.data_a (data_a),
.data_b (data_b),
.wren_a (wren_a),
.wren_b (wren_b),
.q_a (q_a),
.q_b (q_b),
.aclr0 (1'b0),
.aclr1 (1'b0),
.addressstall_a (1'b0),
.addressstall_b (1'b0),
.byteena_a (1'b1),
.byteena_b (1'b1),
.clock1 (1'b1),
.clocken0 (1'b1),
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
.eccstatus (),
.rden_a (1'b1),
.rden_b (1'b1));
defparam
altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0",
altsyncram_component.address_reg_b = "CLOCK0",
altsyncram_component.indata_reg_b = "CLOCK0",
altsyncram_component.numwords_a = NUMWORDS,
altsyncram_component.numwords_b = NUMWORDS,
altsyncram_component.widthad_a = ADDRWIDTH,
altsyncram_component.widthad_b = ADDRWIDTH,
altsyncram_component.width_a = DATAWIDTH,
altsyncram_component.width_b = DATAWIDTH,
altsyncram_component.width_byteena_a = 1,
altsyncram_component.width_byteena_b = 1,
altsyncram_component.init_file = MEM_INIT_FILE,
altsyncram_component.clock_enable_input_a = "BYPASS",
altsyncram_component.clock_enable_input_b = "BYPASS",
altsyncram_component.clock_enable_output_a = "BYPASS",
altsyncram_component.clock_enable_output_b = "BYPASS",
altsyncram_component.intended_device_family = "Cyclone V",
altsyncram_component.lpm_type = "altsyncram",
altsyncram_component.operation_mode = "BIDIR_DUAL_PORT",
altsyncram_component.outdata_aclr_a = "NONE",
altsyncram_component.outdata_aclr_b = "NONE",
altsyncram_component.outdata_reg_a = "UNREGISTERED",
altsyncram_component.outdata_reg_b = "UNREGISTERED",
altsyncram_component.power_up_uninitialized = "FALSE",
altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ";
endmodule

146
rtl/memory/sdram.v Normal file
View File

@ -0,0 +1,146 @@
module sdram
(
// Memory port
input clk,
input cyc,
input curr_cpu,
input [1:0] bsel, // Active HI
input [23:0] A,
input [15:0] DI,
output reg [15:0] DO,
output reg [15:0] DO_cpu,
input REQ,
input RNW,
// SDRAM Pin
inout reg [15:0] SDRAM_DQ,
output reg [12:0] SDRAM_A,
output reg [1:0] SDRAM_BA,
output SDRAM_DQML,
output SDRAM_DQMH,
output SDRAM_nCS,
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nWE,
output SDRAM_CKE,
output SDRAM_CLK
);
reg [2:0] sdr_cmd;
localparam SdrCmd_xx = 3'b111; // no operation
localparam SdrCmd_ac = 3'b011; // activate
localparam SdrCmd_rd = 3'b101; // read
localparam SdrCmd_wr = 3'b100; // write
localparam SdrCmd_pr = 3'b010; // precharge all
localparam SdrCmd_re = 3'b001; // refresh
localparam SdrCmd_ms = 3'b000; // mode regiser set
always @(posedge clk) begin
reg [4:0] state;
reg rd;
reg [8:0] col;
reg [1:0] dqm;
SDRAM_DQ <= 16'hZZZZ;
case (state)
// Init
'h00: begin
sdr_cmd <= SdrCmd_pr; // PRECHARGE
SDRAM_A <= 0;
SDRAM_BA <= 0;
state <= state + 1'd1;
end
// REFRESH
'h03, 'h0A: begin
sdr_cmd <= SdrCmd_re;
state <= state + 1'd1;
end
// LOAD MODE REGISTER
'h11: begin
sdr_cmd <= SdrCmd_ms;
SDRAM_A <= {3'b000, 1'b1, 2'b00, 3'b010, 1'b0, 3'b000};
state <= state + 1'd1;
end
// Idle
'h18: begin
rd <= 0;
if (rd) begin
DO <= SDRAM_DQ;
if (curr_cpu) DO_cpu <= SDRAM_DQ;
end
if(cyc) begin
if (REQ) begin
sdr_cmd <= SdrCmd_ac; // ACTIVE
{SDRAM_A,SDRAM_BA,col} <= A;
dqm <= RNW ? 2'b00 : ~bsel;
rd <= RNW;
state <= state + 1'd1;
end else begin
sdr_cmd <= SdrCmd_re; // REFRESH
state <= 'h13;
end
end
end
// Single read/write - with auto precharge
'h1A: begin
SDRAM_A <= {dqm, 2'b10, col}; // A10 = 1 enable auto precharge; A9..0 = column
state <= 'h16;
if (rd) sdr_cmd <= SdrCmd_rd; // READ
else begin
sdr_cmd <= SdrCmd_wr; // WRITE
SDRAM_DQ <= DI;
end
end
// NOP
default:
begin
sdr_cmd <= SdrCmd_xx;
state <= state + 1'd1;
end
endcase
end
assign SDRAM_CKE = 1;
assign SDRAM_nCS = 0;
assign SDRAM_nRAS = sdr_cmd[2];
assign SDRAM_nCAS = sdr_cmd[1];
assign SDRAM_nWE = sdr_cmd[0];
assign SDRAM_DQML = SDRAM_A[11];
assign SDRAM_DQMH = SDRAM_A[12];
altddio_out
#(
.extend_oe_disable("OFF"),
.intended_device_family("Cyclone V"),
.invert_output("OFF"),
.lpm_hint("UNUSED"),
.lpm_type("altddio_out"),
.oe_reg("UNREGISTERED"),
.power_up_high("OFF"),
.width(1)
)
sdramclk_ddr
(
.datain_h(1'b0),
.datain_l(1'b1),
.outclock(clk),
.dataout(SDRAM_CLK),
.aclr(1'b0),
.aset(1'b0),
.oe(1'b1),
.outclocken(1'b1),
.sclr(1'b0),
.sset(1'b0)
);
endmodule