123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- MODULE DisplayLinear;
- IMPORT SYSTEM, Displays, Plugins, Machine, Kernel, Commands, Options,
- PsConfig, Channels, Video := AcStreamVideoOut, AcAxiDma, Trace;
- CONST
- MaxWidth = 1920;
- MaxHeight = 1080;
- CacheLineSize = 32; (* cache line size in bytes *)
- DmaBurstLen = 16;
- (*
- Video settings for 1024 x 768 @ 62 Hz
- *)
- Width* = 1024;
- Height* = 768;
- PlClkDiv0* = 10;
- PlClkDiv1* = 15;
- PlClkDiv2* = 3;
- HorizFrontPorch* = 24;
- HorizSyncWidth* = 136;
- HorizBackPorch* = 160;
- HorizSyncPolarity* = TRUE;
- VertFrontPorch* = 3;
- VertSyncWidth* = 6;
- VertBackPorch* = 29;
- VertSyncPolarity* = TRUE;
- (*
- (*
- Video settings for 800 x 480 @ 65 Hz
- *)
- Width* = 800;
- Height* = 480;
- PlClkDiv0* = 10;
- PlClkDiv1* = 15*2;
- PlClkDiv2* = 3*2;
- HorizFrontPorch* = 40;
- HorizSyncWidth* = 48;
- HorizBackPorch* = 88;
- HorizSyncPolarity* = TRUE;
- VertFrontPorch* = 13;
- VertSyncWidth* = 3;
- VertBackPorch* = 32;
- VertSyncPolarity* = TRUE;
- *)
- DefaultColor* = LONGINT(0FFFFFFFFH); (** the color of the booting screen *)
- TYPE
- Display = OBJECT(Displays.Display)
- CONST
- Format = 4;
- (** Transfer a block of pixels in "raw" display format to (op = set) or from (op = get) the display. Pixels in the rectangular area are transferred from left to right and top to bottom. The pixels are transferred to or from "buf", starting at "ofs". The line byte increment is "stride", which may be positive, negative or zero. *)
- PROCEDURE Transfer*(VAR buf: ARRAY OF CHAR; ofs, stride, x, y, w, h, op: LONGINT);
- VAR bufadr, buflow, bufhigh, dispadr,w0,b,d: ADDRESS;
- BEGIN
- IF w > 0 THEN
- ASSERT(fbadr # 0);
- bufadr := ADDRESSOF(buf[ofs]);
- dispadr := fbadr + y * fbstride + x * Format;
- IF Displays.reverse THEN
- dispadr := fbadr + (height-y-1) * fbstride + (width-x-1) * Format;
- END;
- ASSERT((dispadr >= fbadr) & ((y+h-1)*fbstride + (x+w-1)*Format <= fbsize)); (* display index check *)
- w := w * Format; (* convert to bytes *)
- CASE op OF
- Displays.set:
- IF Displays.reverse THEN
- WHILE h > 0 DO
- w0 := w DIV Format; b:= bufadr; d := dispadr;
- WHILE w0 > 0 DO
- SYSTEM.MOVE(b, d, Format);
- INC(b,Format);
- DEC(d, Format);
- DEC(w0);
- END;
- INC(bufadr, stride); DEC(dispadr, fbstride);
- DEC(h)
- END
- ELSE
- w0 := w DIV Format;
- WHILE h > 0 DO
- Copy32(bufadr,dispadr,w0); (*SYSTEM.MOVE(bufadr, dispadr, w);*) Machine.FlushDCacheRange(dispadr,w);
- INC(bufadr, stride); INC(dispadr, fbstride);
- DEC(h)
- END
- END;
- |Displays.get:
- IF Displays.reverse THEN
- buflow := ADDRESSOF(buf[0]); bufhigh := buflow + LEN(buf);
- WHILE h > 0 DO
- ASSERT((bufadr >= buflow) & (bufadr+w <= bufhigh)); (* index check *)
- w0 := w DIV Format; b:= bufadr; d := dispadr;
- WHILE w0 > 0 DO
- SYSTEM.MOVE(d, b, Format);
- INC(b,Format);
- DEC(d, Format);
- DEC(w0);
- END;
- INC(bufadr, stride); DEC(dispadr, fbstride);
- DEC(h)
- END;
- ELSE
- buflow := ADDRESSOF(buf[0]); bufhigh := buflow + LEN(buf);
- WHILE h > 0 DO
- ASSERT((bufadr >= buflow) & (bufadr+w <= bufhigh)); (* index check *)
- SYSTEM.MOVE(dispadr, bufadr, w);
- INC(bufadr, stride); INC(dispadr, fbstride);
- DEC(h)
- END;
- END;
- ELSE (* skip *)
- END
- END
- END Transfer;
- END Display;
- VAR
- display: Display;
- vout: Video.Controller;
- pixelClock: REAL; (* pixel clock in Hz *)
- buf: POINTER TO ARRAY OF CHAR;
- bufAddr: ADDRESS;
- rCfgCmd, rCfgData: PORT OUT;
- rStatus: PORT IN;
- videoCfg: PORT OUT;
- rdma: AcAxiDma.ReadController;
- (*
- Reset programming logic
- polarity: reset signal polarity, TRUE for active high and FALSE for active low
- *)
- PROCEDURE ResetPl(polarity: BOOLEAN);
- VAR res, t: LONGINT;
- BEGIN
- IF polarity THEN (* active high *)
- ASSERT(PsConfig.SetPlResets({},res));
- t := Kernel.GetTicks();
- WHILE Kernel.GetTicks() - t < 1 DO END;
- ASSERT(PsConfig.SetPlResets({0..3},res));
- ELSE (* active low *)
- ASSERT(PsConfig.SetPlResets({0..3},res));
- t := Kernel.GetTicks();
- WHILE Kernel.GetTicks() - t < 1 DO END;
- ASSERT(PsConfig.SetPlResets({},res));
- END;
- END ResetPl;
- (*
- Setup clocks required for video streaming
- *)
- PROCEDURE SetupClocks;
- VAR
- res: LONGINT;
- freq: HUGEINT;
- BEGIN
- (*
- Setup DMA frequency
- *)
- freq := PsConfig.GetPllClockFrequency(PsConfig.IoPll,res);
- Trace.String("IO PLL frequency is "); Trace.Int(freq,0); Trace.String(" Hz"); Trace.Ln;
- ASSERT(PsConfig.SetPlResets({0,1,2,3},res));
- IF PsConfig.SetPlClock(0,PsConfig.IoPll,PlClkDiv0,1,res) THEN
- Trace.String("FPGA clock 0 frequency has been changed to "); Trace.Int(PsConfig.GetPlClockFrequency(0,res),0); Trace.String(" Hz"); Trace.Ln;
- ELSE Trace.String("Error while setting FPGA clock 0 frequency, res="); Trace.Int(res,0); Trace.Ln;
- END;
- (*
- Setup display clocks
- *)
- (* pixel clock *)
- pixelClock := REAL(freq)/PlClkDiv1;
- IF PsConfig.SetPlClock(1,PsConfig.IoPll,PlClkDiv1,1,res) THEN
- Trace.String("FPGA clock 1 frequency has been changed to "); Trace.Int(PsConfig.GetPlClockFrequency(1,res),0); Trace.String(" Hz"); Trace.Ln;
- ELSE Trace.String("Error while setting FPGA clock 1 frequency, res="); Trace.Int(res,0); Trace.Ln;
- END;
- (* clock used for serialization *)
- IF PsConfig.SetPlClock(2,PsConfig.IoPll,PlClkDiv2,1,res) THEN
- Trace.String("FPGA clock 2 frequency has been changed to "); Trace.Int(PsConfig.GetPlClockFrequency(2,res),0); Trace.String(" Hz"); Trace.Ln;
- ELSE Trace.String("Error while setting FPGA clock 2 frequency, res="); Trace.Int(res,0); Trace.Ln;
- END;
- END SetupClocks;
- PROCEDURE Init;
- VAR
- res: WORD;
- d: LONGINT;
- BEGIN
- SetupClocks;
- (*
- Reset the programming logic
- *)
- ResetPl(FALSE);
- (*
- Setup ActiveCells components ports
- *)
- ASSERT(Channels.GetOutput(0,0, rCfgCmd));
- ASSERT(Channels.GetOutput(0,1, rCfgData));
- ASSERT(Channels.GetInput(0,0, rStatus));
- ASSERT(Channels.GetOutput(0,2, videoCfg));
- (*
- Allocate frame buffer
- *)
- NEW(buf,CacheLineSize*((MaxHeight*MaxWidth*4+CacheLineSize-1) DIV CacheLineSize)+CacheLineSize);
- bufAddr := ADDRESSOF(buf[0]);
- bufAddr := bufAddr + (CacheLineSize - bufAddr MOD CacheLineSize); (* align to cache line size boundary *)
- Trace.String("DisplayLinear: bufAddr0="); Trace.Hex(ADDRESSOF(buf[0]),-8); Trace.Ln;
- Trace.String("DisplayLinear: bufAddr="); Trace.Hex(bufAddr,-8); Trace.Ln;
- ASSERT(bufAddr MOD CacheLineSize = 0);
- ASSERT(ADDRESSOF(buf[LEN(buf)-1]) >= bufAddr+MaxHeight*MaxWidth*4-1);
- (*
- Setup video streaming
- *)
- Video.InitController(vout,videoCfg,pixelClock);
- Video.SetHorizActiveSize(vout,Width);
- Video.SetHorizFrontPorch(vout,HorizFrontPorch);
- Video.SetHorizSyncWidth(vout,HorizSyncWidth);
- Video.SetHorizBackPorch(vout,HorizBackPorch);
- Video.SetHorizSyncPolarity(vout,HorizSyncPolarity);
- Video.SetVertActiveSize(vout,Height);
- Video.SetVertFrontPorch(vout,VertFrontPorch);
- Video.SetVertSyncWidth(vout,VertSyncWidth);
- Video.SetVertBackPorch(vout,VertBackPorch);
- Video.SetVertSyncPolarity(vout,VertSyncPolarity);
- (*
- Setup AXI DMA for transfering data from the frame buffer to the video output
- *)
- (* configure read channel of S_AXI_HP0 as a 32-bit interface *)
- d := SYSTEM.GET32(0xF8008000); SYSTEM.PUT32(0xF8008000,SYSTEM.MSK(d,0xFFFFFFFE)+1);
-
- Machine.Fill32(bufAddr,Width*Height*4,DefaultColor); (* fill the framebuffer with the default color *)
- Machine.FlushDCacheRange(bufAddr,Width*Height*4);
- AcAxiDma.InitController(rdma,rCfgCmd,rCfgData,rStatus,4,16);
- AcAxiDma.SetBurstLen(rdma,DmaBurstLen);
- (* configure read DMA transfer *)
- AcAxiDma.SetAddr(rdma,bufAddr);
- AcAxiDma.SetCount(rdma,Width*Height);
- AcAxiDma.SetWrap(rdma,TRUE); (* recurring transfer *)
-
- (*
- Enable video output
- *)
- Video.Enable(vout,TRUE);
- AcAxiDma.Start(rdma);
-
- (*
- Install the display
- *)
- NEW(display);
- display.width := Width;
- display.height := Height;
- display.offscreen := 0;
- display.format := 4;
- display.unit := 10000;
- display.InitFrameBuffer(bufAddr,Width*Height*4,Width*4);
- display.desc := "Linear framebuffer driver for Zynq";
- display.Update;
- Displays.registry.Add(display,res);
- ASSERT(res = Plugins.Ok);
- END Init;
- PROCEDURE Install*(context: Commands.Context);
- VAR options: Options.Options;
- BEGIN
- IF context # NIL THEN
- NEW(options);
- options.Add("r", "reverse", Options.Flag);
- IF options.Parse(context.arg, context.error) THEN
- IF options.GetFlag("r") THEN Displays.Reverse() END;
- END;
- END;
- END Install;
- PROCEDURE -Copy32(sadr: ADDRESS; dadr: ADDRESS; len: LONGINT);
- CODE
- LDR R0, [SP, #dadr]
- LDR R1, [SP, #len]
- LDR R2, [SP, #sadr]
- MOV R3, #0
- loop:
- CMP R3, R1
- BGE end
- LDR R4, [R2, #0]
- STR R4, [R0, #0]
- ADD R0, R0, #4
- ADD R2, R2, #4
- ADD R3, R3, #1
- B loop
- end:
- ADD SP, SP, 12
- (*BEGIN
- SYSTEM.MOVE(sadr, dadr, 4*len)*)
- END Copy32;
- BEGIN
- Init;
- END DisplayLinear.
- System.DoCommands
- WinDisks.Install I: RW ~
- FSTools.Mount AOS AosFS PhysicalDrive4#3 ~
- System.DoCommands
- FSTools.CopyFiles -o WORK:/build/DisplayLinear.Gof => AOS:/DisplayLinear.Gof ~
- FSTools.CopyFiles -o WORK:/build/DisplayLinear.Sym => AOS:/DisplayLinear.Sym ~
- FSTools.Unmount AOS ~
- WinDisks.Uninstall PhysicalDrive4 ~
- ~
|