SDRAM Graphic Interface for AVR
這是一個解析度為640 x 480 x 256色的繪圖界面,使用Memory模組模組的Synchronous SDRAM作為frame buffer; VGA模組作為RGB Monitor的輸出, 由CPU模組寫入繪圖界面的暫存器, 間接寫入SDRAM, 做繪圖的動作
Source
-- Top Module
|
sdgfx.v |
|
'timescale 1ns / 100ps
module sdgfx ( hclk,hrst, sa,sba,sdq,sdqm, sckeo,scso, sraso,scaso,sweo, mad,mah, male,mrd,mwr, hsyno,vsyno, vro,vgo,vbo, vbln,vsyc
);
input hclk,hrst; // System clock/reset output[10:0] sa; // SDRAM address output sba; // SDRAM Bank Select inout[15:0] sdq; // SDRAM data port output[1:0] sdqm; // SDRAM mask/byte enable output scso; // SDRAM chip select output sckeo; // SDRAM clock enable output sraso; // SDRAM raw address strobe output scaso; // SDRAM column address strobe output sweo; // SDRAM write enable inout[7:0] mad; // AVR address[7:0]/data input[7:0] mah; // AVR address[15:8] input male; // AVR address latch enable input mrd; // AVR external memory read input mwr; // AVR external memory write output hsyno; // VGA horizontal sync. output vsyno; // VGA vertical sync. output[7:0] vro,vgo,vbo; // VGA R,G,B output output vbln,vsyc; // VGA DAC blank & sync signal, assigned to 1
reg[9:0] hcnt; reg hov,hsyns,hsyne,enlbis,enlbie, enlbos,enlboe,enmps,enmpe; reg hsyn,enlbi,enlbo,enlbox,enmp; reg[9:0] vcnt; reg vov,vens,vene,vsyns,vsyne; reg vsyn,ven; reg scmd,slbr,smpw,sburst; reg swrites,sreads; reg[8:0] sms,nsms; wire hwff,hwfe; reg hwfrd; wire[31:0] hwfdo; reg scs,sras,scas,swe; wire[7:0] sdcra; reg[23:0] sadp; reg[10:0] sad; reg sbank; reg[4:0] srdph; reg[1:0] sqm; reg sdqoe; reg[15:0] sdqo; reg[15:0] sdqis; wire[7:0] lbdo; reg[7:0] vdata; wire[7:0] mado;
// Host Interface & Write FIFO mwfifo mwfifo ( .hclk(hclk),.hrst(hrst), .mah(mah),.madi(mad),.mado(mado), .male(male),.mwr(mwr),.mrd(mrd), .hwfrd(hwfrd),.hwfdo(hwfdo), .hwff(hwff),.hwfe(hwfe), .sdcra(sdcra) );
// Display Read Line Buffer lbfifo lbfifo ( .hclk(hclk),.hrst(hrst), .lbdi(sdqis),.lbdo(lbdo), .lbrd(enlbo),.lbwr(srdph[3]) );
// Horizontal counter always @(posedge hclk or negedge hrst) begin if(~hrst) hcnt<=0; else begin if(hov|~sdcra[0]) hcnt<=0; else hcnt<=hcnt+1; end end
// Horizontal control signals always @(posedge hclk) begin hov<=(hcnt==795); // horizontal counter overflow hsyns<=(hcnt==652); // VGA HSYNC start hsyne<=(hcnt==747); // VGA HSYNC end enlbis<=(hcnt==1); // Start of Enable Line Buffer In/read enlbie<=(hcnt==259); // End of Enable Line Buffer In/read enlbos<=(hcnt==10); // Start of Enable Line Buffer to VGA Out enlboe<=(hcnt==522); // End of Enable Line Buffer to VGA Out enmps<=(hcnt==280); // Start of Enable Micro-Processor access enmpe<=(hcnt==775); // End of Enable Mirco-Processor access end
// VGA HSYNC always @(posedge hclk or negedge hrst) begin if(~hrst) hsyn<=1'b0; else begin case(hsyn) 1'b0 : if(hsyns) hsyn<=1'b1; 1'b1 : if(hsyne) hsyn<=1'b0; endcase end end
// Enable Line Buffer In/read always @(posedge hclk or negedge hrst) begin if(~hrst) enlbi<=1'b0; else begin case(enlbi) 1'b0 : if(enlbis&ven) enlbi<=1'b1; 1'b1 : if(enlbie) enlbi<=1'b0; endcase end end
// Enable Line Buffer to VGA Out always @(posedge hclk or negedge hrst) begin if(~hrst) begin enlbo<=1'b0; enlbox<=1'b0; end else begin case(enlbo) 1'b0 : if(enlbos&ven) enlbo<=1'b1; 1'b1 : if(enlboe) enlbo<=1'b0; endcase enlbox<=enlbo; end end
// Enable Micro-Processor Access always @(posedge hclk or negedge hrst) begin if(~hrst) enmp<=1'b0; else begin case(enmp) 1'b0 : if(enmps) enmp<=1'b1; 1'b1 : if(enmpe) enmp<=1'b0; endcase end end
// Vertical counter always @(posedge hclk or negedge hrst) begin if(~hrst) vcnt<=0; else if(hsyns) begin if(vov) vcnt<=0; else vcnt<=vcnt+1; end end
// Vertical control signals always @(posedge hclk) begin vov<=(vcnt==522); // Vertical counter overflow vens<=(vcnt==1); // Start of Vertical Enable vene<=(vcnt==481); // End of Vertical Enable vsyns<=(vcnt==490); // Start of VGA VSYNC vsyne<=(vcnt==492); // End of VGA VSYNC end
// VGA VSYNC always @(posedge hclk or negedge hrst) begin if(~hrst) vsyn<=1'b0; else begin case(vsyn) 1'b0 : if(vsyns) vsyn<=1'b1; 1'b1 : if(vsyne) vsyn<=1'b0; endcase end end
// Vertical Enable, indicates valid horizontal cycles (line 0 to 479) always @(posedge hclk or negedge hrst) begin if(~hrst) ven<=1'b0; else begin case(ven) 1'b0 : if(vens) ven<=1'b1; 1'b1 : if(vene) ven<=1'b0; endcase end end
// Control Signals for SDRAM Controller always @(posedge hclk or negedge hrst) begin if(~hrst) begin slbr<=1'b0; smpw<=1'b0; scmd<=1'b0; sburst<=1'b0; swrites<=1'b0; sreads<=1'b0; end else begin slbr<=enlbi&sdcra[0]; // SDRAM Line Buffer Read smpw<=enmp&~hwfe&sdcra[0]; // SDRAM Micro-Processor Write scmd<=~hwfe&~sdcra[0]; // SDRAM Command(PRE/REF/SetMode) from Micro-Processor sburst<=enlbi&sdcra[0]; // SDRAM Burst Access if(sms[0]) begin swrites<=smpw; sreads<=slbr; end // SDRAM Write/Read end end
// Read control signal for Host FIFO always @(scmd or smpw or sms) begin hwfrd=(scmd&sms[7])|(smpw&(sms[3]|sms[4])); end
// SDRAM Controller State Machine always @(posedge hclk or negedge hrst) begin if(~hrst) sms<='b000000001; else sms<=nsms; end
always @(sms or slbr or smpw or scmd or sburst) begin casex(sms) 'bxxxxxxxx1 : begin if(slbr|smpw) nsms='b000000010; else if(scmd) nsms='b010000000; else nsms='b000000001; end 'bxxxxxxx1x : begin nsms='b000000100; end // ras 'bxxxxxx1xx : begin nsms='b000001000; end // nop 'bxxxxx1xxx : begin if(sburst) nsms='b000010000; // cas else nsms='b000100000; end 'bxxxx1xxxx : begin if(sburst)nsms='b000010000; // nop burst; else nsms='b000100000; end 'bxxx1xxxxx : begin nsms='b001000000; end // pre 'bxx1xxxxxx : begin nsms='b000000001; end // nop 'bx1xxxxxxx : begin nsms='b100000000; end // cmd -- pre/ref/setmode 'b1xxxxxxxx : begin nsms='b000000001; end // nop default : begin nsms='b000000001; end endcase end
// SDRAM Control Signals always @(posedge hclk) begin scs<=~(sms[1]|sms[3]|sms[5]|sms[7]&sdcra[4]); // SDRAM Chip Select sras<=~(sms[1]|sms[5]|sms[7]&sdcra[3]); // SDRAM Raw Address Strobe scas<=~(sms[3]|sms[7]&sdcra[2]); // SDRAM Column Address Strobe swe<=~(sms[3]&swrites|sms[5]|sms[7]&sdcra[1]); // SDRAM Write Enable end
// SDRAM Read Strobe Delay Slots always @(posedge hclk) begin srdph<={srdph[3:0],(sms[3]|sms[4])&sreads}; end
// SDRAM Data Mask(Byte Enable) always @(posedge hclk) begin sqm<={~((sms[3]|sms[4])&(sreads|swrites&sadp[0])), ~((sms[3]|sms[4])&(sreads|swrites&~sadp[0]))}; end
// SDRAM Data Output Enable always @(posedge hclk) begin sdqoe<=(sms[3]|sms[4])&swrites; end
// Internal Address for SDRAM Space always @(posedge hclk) begin if(sms[0]) sadp<=(slbr)?{5'h0,vcnt,9'h0}:hwfdo[31:8]; end
// SDRAM Data Output, not valid for write burst always @(posedge hclk) begin if(sms[3]|sms[4]) sdqo<={hwfdo[7:0],hwfdo[7:0]}; end
// setmode : host/reg mapping -> // reg[2:0] : sadp[11:9]=mpa[11:9], Burst length // reg[3] : sadp[12]=mpa[12], Burst Type S/I // reg[6:4] : sadp[15:13]={mpg[0],mpa[14:13]}, CAS latency // reg[8:7] : sadp[17:16]=mpg[2:1], Mode=2'b00 // reg[9] : sadp[18]=mpg[3], R/W Burst // reg[11:10] : sadp[20:19]=mpg[5:4], 2'b00
// SDRAM Address/Bank Output always @(posedge hclk) begin sad<=(sms[0]|sms[1]|sms[7])?sadp[19:9]: {sms[5],2'b00,sadp[8:1]}; sbank<=sadp[20]; end
// SDRAM Data Input Latch always @(posedge hclk) begin sdqis<=sdq[15:0]; end
// VGA Data Latched from Line Buffer always @(posedge hclk) begin vdata<=enlbox?lbdo:8'h00; end
// VGA R/G/B Outputs assign vro={vdata[7:5],5'b0}; assign vgo={vdata[4:2],5'b0}; assign vbo={vdata[1:0],6'b0};
// Misc. Output Ports ( #2 delays are for SDRAM Model timing check in RTL-Sim ) assign hsyno=hsyn,vsyno=vsyn;
assign #2 sckeo=1'b1; assign #2 scso=1'b0;
assign #2 sraso=sras; assign #2 scaso=scas; assign #2 sweo=swe;
assign #2 sa=sad; assign #2 sba=sbank;
assign #2 sdqm=sqm;
assign #2 sdq[15:0]=sdqoe?sdqo:16'hz;
assign vbln=1'b1; assign vsyc=1'b1;
assign mad=mrd?8'hzz:mado;
endmodule
|
-- VGA Read Buffer
|
lbfifo.v |
|
'timescale 1ns / 100ps
module lbfifo ( hclk,hrst, lbdi,lbdo, lbrd,lbwr );
input hclk,hrst; input[15:0] lbdi; output[7:0] lbdo; input lbrd,lbwr;
reg[7:0] fwp; reg[8:0] frp;
always @(posedge hclk or negedge hrst) begin if(~hrst) fwp<=0; else if(lbwr) fwp<=fwp+1; end
always @(posedge hclk or negedge hrst) begin if(~hrst) frp<=0; else if(lbrd) frp<=frp+1; end
// RAM by Instanciation of Xilinx Library Cell /*RAMB4_S8_S16 ffram1 ( .CLKB(hclk),.RSTB(~hrst),.ENB(1'b1),.ADDRB(fwp), .WEB(lbwr),.DIB(lbdi),.DOB(), .CLKA(hclk),.RSTA(~hrst),.ENA(1'b1),.ADDRA(frp), .WEA(1'b0),.DIA(8'b0),.DOA(lbdo) );*/
ram8dp ffram0 ( .mclk(hclk),.wa(fwp), .wen(lbwr),.din(lbdi), .ra(frp),.dout(lbdo) );
endmodule
|
-- Host Write Fifo
|
hwfifo.v |
|
'timescale 1ns / 100ps
module mwfifo ( hclk,hrst, mah,madi,mado, male,mwr,mrd, hwfrd,hwfdo,hwff,hwfe, sdcra );
input hclk,hrst; input[7:0] mah; input[7:0] madi; output[7:0] mado;
input male,mwr,mrd; input hwfrd; output[31:0] hwfdo; output hwff,hwfe; output[7:0] sdcra;
reg[7:0] mal; reg mwrs,mwrss; wire mwrp; reg[7:0] mapg; reg[7:0] sdcra; reg[7:0] mado; wire[31:0] ffwdt; wire ffwea; reg[8:0] frp,fwp; wire hwff,hwfe;
always @(negedge male) mal<=madi;
always @(posedge hclk or negedge hrst) begin if(~hrst) begin mwrs<=1'b1; mwrss<=1'b1; end else begin mwrs<=mwr; mwrss<=mwrs; end end
assign mwrp=mwrss&~mwrs;
// Control Registers for SDRAM Controller always @(posedge hclk or negedge hrst) begin if(~hrst) begin mapg<=8'h00; sdcra<=8'h00; end else begin if(mwrp&(mah[7:6]==1)&(mal[1:0]==0)) mapg<=madi; if(mwrp&(mah[7:6]==1)&(mal[1:0]==1)) sdcra<=madi; end end
// Status of FIFO read by host always @(mah or mal or hwfe or hwff) begin case(mah[7:6]) 1 : begin case(mal[1:0]) 0 : mado={6'b000000,hwfe,hwff}; default : mado=8'h00; endcase end default : mado=8'h00; endcase end
assign #2 ffwdt={1'b0,mapg,mah[6:0],mal,madi}; assign #2 ffwea=mwrp&mah[7];
always @(posedge hclk or negedge hrst) begin if(~hrst) #2 frp<=0; else if(hwfrd) #2 frp<=frp+1; end
always @(posedge hclk or negedge hrst) begin if(~hrst) #2 fwp<=0; else if(ffwea) #2 fwp<=fwp+1; end
assign hwff=(fwp[8]!=frp[8])&(fwp[7:0]==frp[7:0]); assign hwfe=(fwp==frp);
ram32dp ffram0 ( .mclk(hclk),.wa(fwp[7:0]), .wen(ffwea),.din(ffwdt[31:0]), .ra(frp[7:0]),.dout(hwfdo[31:0]) );
endmodule
|
-- Write 256x16; Read:512x8, Dual Port RAM
|
ram8dp.v |
|
'timescale 1ns / 100ps
// Behavior RAM Module, could be synthesized by Xilinx XIST, Leonardo, but not by Synopsys module ram8dp ( mclk, ra,wa, wen, din,dout
);
input mclk; input[8:0] ra; input[7:0] wa; input wen; input[15:0] din; output[7:0] dout;
wire[15:0] rout; reg[7:0] dout;
reg[15:0] mem[0:255];
always @(posedge mclk) begin if(wen) mem[wa]<=din; end
assign rout=mem[ra[8:1]];
always @(posedge mclk) begin dout<=ra[0]?rout[15:8]:rout[7:0]; end
endmodule
|
-- 256x32 Dual Port RAM
|
ram32dp.v |
|
'timescale 1ns / 100ps
module ram32dp ( mclk, ra,wa, wen, din,dout
);
input mclk; input[7:0] ra,wa; input wen; input[31:0] din; output[31:0] dout;
reg[31:0] dout;
reg[31:0] mem[0:255];
always @(posedge mclk) begin if(wen) mem[wa]<=din; dout<=mem[ra]; end
endmodule
|
-- Test Bench
|
tsdgfx.v |
|
'timescale 1ns / 100ps
module tsdgfx ();
reg hclk,hrst; wire[10:0] sa; wire sba; wire[15:0] sdq; wire[1:0] sdqm; wire scs,sras,scas,swe; wire[7:0] mad; reg[7:0] mado; reg[7:0] mah; reg male,mrd,mwr;
task mpwr; input[15:0] addr; input[7:0] data; begin male=1'b1; #10; mah=addr[15:8]; mado=addr[7:0]; #22.5; male=1'b0; #67.5; mado=data; #27.5; mwr=1'b0; #167.5; mwr=1'b1; mado=8'hzz; mah=8'hxx; #22.5; end endtask
assign mad=mado;
initial begin hclk=1'b0; hrst=1'b0; mwr=1'b1; mrd=1'b1; mah=8'hxx; mado=8'hzz; male=1'b0; #200; hrst=1'b1; #3000;
mpwr('h4000,'h10); mpwr('h4001,'b00011010); // pre mpwr('h8000,'h00); #2000; mpwr('h4000,'h00); mpwr('h4001,'b00011110); // setmode mpwr('hce00,'h00); #2000; mpwr('h4001,'b00011100); // ARef mpwr('h8000,'h00); #2000; mpwr('h4000,'h00); mpwr('h4001,'b00011100); // ARef mpwr('h8000,'h00); #2000;
#30000; mpwr('h4001,'b00000001); #30000; begin : mpblock integer ii; for(ii=0;ii<'h200;ii=ii+1) begin mpwr('ha000+ii,'h00-ii); #200; end end
#300000;
$stop; end
always #20 hclk=~hclk;
sdgfx u0(.hclk(hclk),.hrst(hrst), .sa(sa),.sba(sba), .sdq(sdq),.sdqm(sdqm), .sckeo(scke),.scso(scs), .sraso(sras),.scaso(scas),.sweo(swe), .mad(mad),.mah(mah), .male(male),.mrd(mrd),.mwr(mwr), .hsyno(),.vsyno(), .vro(),.vgo(),.vbo(),.vbln(),.vsyc() );
mt48lc1m16a1 sdu0(sdq, sa, sba, hclk, scke, scs, sras, scas, swe, sdqm);
endmodule
|
-- AVR ASM Program
|
tstgfx.asm |
|
.include "8515def.inc"
rjmp Reset
.org $010 Reset: ldi r16,LOW(RAMEND) out SPL,r16 ldi r16,HIGH(RAMEND) out SPL+1,r16 ldi r16,0b11000000 out MCUCR,r16 ldi YH,$80 ldi YL,$00 eor r20,r20 eor r21,r21 eor r22,r22 eor r23,r23 l0: rcall setcolor l1: rcall plotxy inc r21 brne l1 inc r23 inc r22 brne l0 inc r23 inc r20 rjmp l0
setcolor: std y+2,r23 ldi r16,$00 std y+3,r16 ret
plotxy: st y,r20 std y+1,r21 std y+2,r22 pl0: sbic PIND,2 rjmp pl0 ldi r16,$03 std y+3,r16 ret
|
-- Port Signals of sramgfx
|
signal |
type |
Description |
|
hclk |
IN |
System clock |
|
hrst |
IN |
System reset |
|
sa[10:0] |
OUT |
SDRAM address |
|
sba |
OUT |
SDRAM Bank Select |
|
sdqm[1:0] |
OUT |
SDRAM mask/byte enable |
|
scso |
OUT |
SDRAM chip select |
|
sckeo |
OUT |
SDRAM clock enable |
|
sraso |
OUT |
SDRAM raw address strobe |
|
scaso |
OUT |
SDRAM column address strobe |
|
sweo |
OUT |
SDRAM write enable |
|
mad[7:0] |
INOUT |
AVR address[7:0]/data |
|
mah[7:0] |
IN |
AVR address[15:8] |
|
male |
IN |
AVR address latch enable |
|
mrd |
IN |
AVR external memory read |
|
mwr |
IN |
AVR external memory write |
|
hsyno |
OUT |
VGA horizontal sync |
|
vsyno |
OUT |
VGA vertical sync |
|
vro[7:0] |
OUT |
VGA R output |
|
vgo[7:0] |
OUT |
VGA G output |
|
vbo[7:0] |
OUT |
VGA B output |
|
vbln |
OUT |
VGA DAC blank & sync signal, assigned to 1 |
|
vsyc |
OUT |
VGA DAC blank & sync signal, assigned to 1 |
-- Internal Signals of sramg fx
|
signal |
Description |
|
hcnt[9:0] |
Horizontal counter |
|
hov |
horizontal counter overflow |
|
hsyns |
VGA HSYNC start |
|
hsyne |
VGA HSYNC end |
|
enblis |
Start of Enable Line Buffer In/read |
|
enblie |
End of Enable Line Buffer In/read |
|
enblos |
Start of Enable Line Buffer to VGA Out |
|
enbloe |
End of Enable Line Buffer to VGA Out |
|
enmps |
Start of Enable Micro-Processor access |
|
enmpe |
End of Enable Mirco-Processor access |
|
hsyn |
VGA HSYNC |
|
enlbi |
Enable Line Buffer In/read |
|
enblo |
Enable Line Buffer to VGA Out |
|
enmp |
Enable Micro-Processor Access |
|
vcnt[9:0] |
Vertical counter |
|
vov |
Vertical counter overflow |
|
vens |
Start of Vertical Enable |
|
vene |
End of Vertical Enable |
|
vsyns |
Start of VGA VSYNC |
|
vsyne |
End of VGA VSYNC |
|
vsyn |
VGA VSYNC |
|
ven |
Vertical Enable, indicates valid horizontal cycles (line 0 to 479) |
|
scmd |
SDRAM Command(PRE/REF/SetMode) from Micro-Processor |
|
slbr |
SDRAM Line Buffer Read |
|
smpw |
SDRAM Micro-Processor Write |
|
sburst |
SDRAM Burst Access |
|
swrites |
Write type SDRAM Access |
|
sreads |
Read type SDRAM Access |
|
sms[8:0] |
SDRAM Controller State Machine State Registers |
|
nsms[8:0] |
SDRAM Controller State Machine Next State Signals |
|
hwff |
Host Write FIFO Full |
|
hwfe |
Host Write FIFO Empty |
|
hwfrd |
Read control signal for Host FIFO |
|
hwfdo |
Host Write FIFO Data Out |
|
scs |
SDRAM Chip Select |
|
sras |
SDRAM Raw Address Strobe |
|
scas |
SDRAM Column Address Strobe |
|
swe |
SDRAM Write Enable |
|
sdcra[7:0] |
SDRAM Control Register 0:Cmd/Normal, 4~1:(scs,sras,scas,swe) in Cmd mode |
|
sadp[23:0] |
Internal Address for SDRAM Space |
|
sad[10:0] |
SDRAM Address Output |
|
sbank |
SDRAM Bank Select Output |
|
srdph[4:0] |
SDRAM Read Strobe Delay Slots |
|
sqm[1:0] |
SDRAM Data Mask(Byte Enable) |
|
sdqoe |
SDRAM Data Output Enable |
|
sdqo[15:0] |
SDRAM Data Output, not valid for write burst |
|
sdqis[15:0] |
SDRAM Data Input Latch |
|
lbdo[7:0] |
Line Buffer Read FIFO Data Out |
|
vdata[7:0] |
VGA Data Latched from Line Buffer |
|
mado[7:0] |
Micro-Processor Read Data Out |
