Zynq.DisplayLinear.Mod 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. MODULE DisplayLinear;
  2. IMPORT SYSTEM, Displays, Plugins, Machine, Kernel, Commands, Options,
  3. PsConfig, Channels, Video := AcStreamVideoOut, AcAxiDma, Trace;
  4. CONST
  5. MaxWidth = 1920;
  6. MaxHeight = 1080;
  7. CacheLineSize = 32; (* cache line size in bytes *)
  8. DmaBurstLen = 16;
  9. (*
  10. Video settings for 1024 x 768 @ 62 Hz
  11. *)
  12. Width* = 1024;
  13. Height* = 768;
  14. PlClkDiv0* = 10;
  15. PlClkDiv1* = 15;
  16. PlClkDiv2* = 3;
  17. HorizFrontPorch* = 24;
  18. HorizSyncWidth* = 136;
  19. HorizBackPorch* = 160;
  20. HorizSyncPolarity* = TRUE;
  21. VertFrontPorch* = 3;
  22. VertSyncWidth* = 6;
  23. VertBackPorch* = 29;
  24. VertSyncPolarity* = TRUE;
  25. (*
  26. (*
  27. Video settings for 800 x 480 @ 65 Hz
  28. *)
  29. Width* = 800;
  30. Height* = 480;
  31. PlClkDiv0* = 10;
  32. PlClkDiv1* = 15*2;
  33. PlClkDiv2* = 3*2;
  34. HorizFrontPorch* = 40;
  35. HorizSyncWidth* = 48;
  36. HorizBackPorch* = 88;
  37. HorizSyncPolarity* = TRUE;
  38. VertFrontPorch* = 13;
  39. VertSyncWidth* = 3;
  40. VertBackPorch* = 32;
  41. VertSyncPolarity* = TRUE;
  42. *)
  43. DefaultColor* = LONGINT(0FFFFFFFFH); (** the color of the booting screen *)
  44. TYPE
  45. Display = OBJECT(Displays.Display)
  46. CONST
  47. Format = 4;
  48. (** 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. *)
  49. PROCEDURE Transfer*(VAR buf: ARRAY OF CHAR; ofs, stride, x, y, w, h, op: LONGINT);
  50. VAR bufadr, buflow, bufhigh, dispadr,w0,b,d: ADDRESS;
  51. BEGIN
  52. IF w > 0 THEN
  53. ASSERT(fbadr # 0);
  54. bufadr := ADDRESSOF(buf[ofs]);
  55. dispadr := fbadr + y * fbstride + x * Format;
  56. IF Displays.reverse THEN
  57. dispadr := fbadr + (height-y-1) * fbstride + (width-x-1) * Format;
  58. END;
  59. ASSERT((dispadr >= fbadr) & ((y+h-1)*fbstride + (x+w-1)*Format <= fbsize)); (* display index check *)
  60. w := w * Format; (* convert to bytes *)
  61. CASE op OF
  62. Displays.set:
  63. IF Displays.reverse THEN
  64. WHILE h > 0 DO
  65. w0 := w DIV Format; b:= bufadr; d := dispadr;
  66. WHILE w0 > 0 DO
  67. SYSTEM.MOVE(b, d, Format);
  68. INC(b,Format);
  69. DEC(d, Format);
  70. DEC(w0);
  71. END;
  72. INC(bufadr, stride); DEC(dispadr, fbstride);
  73. DEC(h)
  74. END
  75. ELSE
  76. w0 := w DIV Format;
  77. WHILE h > 0 DO
  78. Copy32(bufadr,dispadr,w0); (*SYSTEM.MOVE(bufadr, dispadr, w);*) Machine.FlushDCacheRange(dispadr,w);
  79. INC(bufadr, stride); INC(dispadr, fbstride);
  80. DEC(h)
  81. END
  82. END;
  83. |Displays.get:
  84. IF Displays.reverse THEN
  85. buflow := ADDRESSOF(buf[0]); bufhigh := buflow + LEN(buf);
  86. WHILE h > 0 DO
  87. ASSERT((bufadr >= buflow) & (bufadr+w <= bufhigh)); (* index check *)
  88. w0 := w DIV Format; b:= bufadr; d := dispadr;
  89. WHILE w0 > 0 DO
  90. SYSTEM.MOVE(d, b, Format);
  91. INC(b,Format);
  92. DEC(d, Format);
  93. DEC(w0);
  94. END;
  95. INC(bufadr, stride); DEC(dispadr, fbstride);
  96. DEC(h)
  97. END;
  98. ELSE
  99. buflow := ADDRESSOF(buf[0]); bufhigh := buflow + LEN(buf);
  100. WHILE h > 0 DO
  101. ASSERT((bufadr >= buflow) & (bufadr+w <= bufhigh)); (* index check *)
  102. SYSTEM.MOVE(dispadr, bufadr, w);
  103. INC(bufadr, stride); INC(dispadr, fbstride);
  104. DEC(h)
  105. END;
  106. END;
  107. ELSE (* skip *)
  108. END
  109. END
  110. END Transfer;
  111. END Display;
  112. VAR
  113. display: Display;
  114. vout: Video.Controller;
  115. pixelClock: REAL; (* pixel clock in Hz *)
  116. buf: POINTER TO ARRAY OF CHAR;
  117. bufAddr: ADDRESS;
  118. rCfgCmd, rCfgData: PORT OUT;
  119. rStatus: PORT IN;
  120. videoCfg: PORT OUT;
  121. rdma: AcAxiDma.ReadController;
  122. (*
  123. Reset programming logic
  124. polarity: reset signal polarity, TRUE for active high and FALSE for active low
  125. *)
  126. PROCEDURE ResetPl(polarity: BOOLEAN);
  127. VAR res, t: LONGINT;
  128. BEGIN
  129. IF polarity THEN (* active high *)
  130. ASSERT(PsConfig.SetPlResets({},res));
  131. t := Kernel.GetTicks();
  132. WHILE Kernel.GetTicks() - t < 1 DO END;
  133. ASSERT(PsConfig.SetPlResets({0..3},res));
  134. ELSE (* active low *)
  135. ASSERT(PsConfig.SetPlResets({0..3},res));
  136. t := Kernel.GetTicks();
  137. WHILE Kernel.GetTicks() - t < 1 DO END;
  138. ASSERT(PsConfig.SetPlResets({},res));
  139. END;
  140. END ResetPl;
  141. (*
  142. Setup clocks required for video streaming
  143. *)
  144. PROCEDURE SetupClocks;
  145. VAR
  146. res: LONGINT;
  147. freq: HUGEINT;
  148. BEGIN
  149. (*
  150. Setup DMA frequency
  151. *)
  152. freq := PsConfig.GetPllClockFrequency(PsConfig.IoPll,res);
  153. Trace.String("IO PLL frequency is "); Trace.Int(freq,0); Trace.String(" Hz"); Trace.Ln;
  154. ASSERT(PsConfig.SetPlResets({0,1,2,3},res));
  155. IF PsConfig.SetPlClock(0,PsConfig.IoPll,PlClkDiv0,1,res) THEN
  156. Trace.String("FPGA clock 0 frequency has been changed to "); Trace.Int(PsConfig.GetPlClockFrequency(0,res),0); Trace.String(" Hz"); Trace.Ln;
  157. ELSE Trace.String("Error while setting FPGA clock 0 frequency, res="); Trace.Int(res,0); Trace.Ln;
  158. END;
  159. (*
  160. Setup display clocks
  161. *)
  162. (* pixel clock *)
  163. pixelClock := REAL(freq)/PlClkDiv1;
  164. IF PsConfig.SetPlClock(1,PsConfig.IoPll,PlClkDiv1,1,res) THEN
  165. Trace.String("FPGA clock 1 frequency has been changed to "); Trace.Int(PsConfig.GetPlClockFrequency(1,res),0); Trace.String(" Hz"); Trace.Ln;
  166. ELSE Trace.String("Error while setting FPGA clock 1 frequency, res="); Trace.Int(res,0); Trace.Ln;
  167. END;
  168. (* clock used for serialization *)
  169. IF PsConfig.SetPlClock(2,PsConfig.IoPll,PlClkDiv2,1,res) THEN
  170. Trace.String("FPGA clock 2 frequency has been changed to "); Trace.Int(PsConfig.GetPlClockFrequency(2,res),0); Trace.String(" Hz"); Trace.Ln;
  171. ELSE Trace.String("Error while setting FPGA clock 2 frequency, res="); Trace.Int(res,0); Trace.Ln;
  172. END;
  173. END SetupClocks;
  174. PROCEDURE Init;
  175. VAR
  176. res: WORD;
  177. d: LONGINT;
  178. BEGIN
  179. SetupClocks;
  180. (*
  181. Reset the programming logic
  182. *)
  183. ResetPl(FALSE);
  184. (*
  185. Setup ActiveCells components ports
  186. *)
  187. ASSERT(Channels.GetOutput(0,0, rCfgCmd));
  188. ASSERT(Channels.GetOutput(0,1, rCfgData));
  189. ASSERT(Channels.GetInput(0,0, rStatus));
  190. ASSERT(Channels.GetOutput(0,2, videoCfg));
  191. (*
  192. Allocate frame buffer
  193. *)
  194. NEW(buf,CacheLineSize*((MaxHeight*MaxWidth*4+CacheLineSize-1) DIV CacheLineSize)+CacheLineSize);
  195. bufAddr := ADDRESSOF(buf[0]);
  196. bufAddr := bufAddr + (CacheLineSize - bufAddr MOD CacheLineSize); (* align to cache line size boundary *)
  197. Trace.String("DisplayLinear: bufAddr0="); Trace.Hex(ADDRESSOF(buf[0]),-8); Trace.Ln;
  198. Trace.String("DisplayLinear: bufAddr="); Trace.Hex(bufAddr,-8); Trace.Ln;
  199. ASSERT(bufAddr MOD CacheLineSize = 0);
  200. ASSERT(ADDRESSOF(buf[LEN(buf)-1]) >= bufAddr+MaxHeight*MaxWidth*4-1);
  201. (*
  202. Setup video streaming
  203. *)
  204. Video.InitController(vout,videoCfg,pixelClock);
  205. Video.SetHorizActiveSize(vout,Width);
  206. Video.SetHorizFrontPorch(vout,HorizFrontPorch);
  207. Video.SetHorizSyncWidth(vout,HorizSyncWidth);
  208. Video.SetHorizBackPorch(vout,HorizBackPorch);
  209. Video.SetHorizSyncPolarity(vout,HorizSyncPolarity);
  210. Video.SetVertActiveSize(vout,Height);
  211. Video.SetVertFrontPorch(vout,VertFrontPorch);
  212. Video.SetVertSyncWidth(vout,VertSyncWidth);
  213. Video.SetVertBackPorch(vout,VertBackPorch);
  214. Video.SetVertSyncPolarity(vout,VertSyncPolarity);
  215. (*
  216. Setup AXI DMA for transfering data from the frame buffer to the video output
  217. *)
  218. (* configure read channel of S_AXI_HP0 as a 32-bit interface *)
  219. d := SYSTEM.GET32(0xF8008000); SYSTEM.PUT32(0xF8008000,SYSTEM.MSK(d,0xFFFFFFFE)+1);
  220. Machine.Fill32(bufAddr,Width*Height*4,DefaultColor); (* fill the framebuffer with the default color *)
  221. Machine.FlushDCacheRange(bufAddr,Width*Height*4);
  222. AcAxiDma.InitController(rdma,rCfgCmd,rCfgData,rStatus,4,16);
  223. AcAxiDma.SetBurstLen(rdma,DmaBurstLen);
  224. (* configure read DMA transfer *)
  225. AcAxiDma.SetAddr(rdma,bufAddr);
  226. AcAxiDma.SetCount(rdma,Width*Height);
  227. AcAxiDma.SetWrap(rdma,TRUE); (* recurring transfer *)
  228. (*
  229. Enable video output
  230. *)
  231. Video.Enable(vout,TRUE);
  232. AcAxiDma.Start(rdma);
  233. (*
  234. Install the display
  235. *)
  236. NEW(display);
  237. display.width := Width;
  238. display.height := Height;
  239. display.offscreen := 0;
  240. display.format := 4;
  241. display.unit := 10000;
  242. display.InitFrameBuffer(bufAddr,Width*Height*4,Width*4);
  243. display.desc := "Linear framebuffer driver for Zynq";
  244. display.Update;
  245. Displays.registry.Add(display,res);
  246. ASSERT(res = Plugins.Ok);
  247. END Init;
  248. PROCEDURE Install*(context: Commands.Context);
  249. VAR options: Options.Options;
  250. BEGIN
  251. IF context # NIL THEN
  252. NEW(options);
  253. options.Add("r", "reverse", Options.Flag);
  254. IF options.Parse(context.arg, context.error) THEN
  255. IF options.GetFlag("r") THEN Displays.Reverse() END;
  256. END;
  257. END;
  258. END Install;
  259. PROCEDURE -Copy32(sadr: ADDRESS; dadr: ADDRESS; len: LONGINT);
  260. CODE
  261. LDR R0, [SP, #dadr]
  262. LDR R1, [SP, #len]
  263. LDR R2, [SP, #sadr]
  264. MOV R3, #0
  265. loop:
  266. CMP R3, R1
  267. BGE end
  268. LDR R4, [R2, #0]
  269. STR R4, [R0, #0]
  270. ADD R0, R0, #4
  271. ADD R2, R2, #4
  272. ADD R3, R3, #1
  273. B loop
  274. end:
  275. ADD SP, SP, 12
  276. (*BEGIN
  277. SYSTEM.MOVE(sadr, dadr, 4*len)*)
  278. END Copy32;
  279. BEGIN
  280. Init;
  281. END DisplayLinear.
  282. System.DoCommands
  283. WinDisks.Install I: RW ~
  284. FSTools.Mount AOS AosFS PhysicalDrive4#3 ~
  285. System.DoCommands
  286. FSTools.CopyFiles -o WORK:/build/DisplayLinear.Gof => AOS:/DisplayLinear.Gof ~
  287. FSTools.CopyFiles -o WORK:/build/DisplayLinear.Sym => AOS:/DisplayLinear.Sym ~
  288. FSTools.Unmount AOS ~
  289. WinDisks.Uninstall PhysicalDrive4 ~
  290. ~