Firmware for MNT ZZ9000 graphics and ARM coprocessor card for Amiga computers.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

474 wiersze
13 KiB

  1. `timescale 1ns / 1ps
  2. /*
  3. * MNT ZZ9000 Amiga Graphics and Coprocessor Card Firmware
  4. * Video Stream Formatter
  5. *
  6. * Copyright (C) 2019-2020, Lukas F. Hartmann <lukas@mntre.com>
  7. * MNT Research GmbH, Berlin
  8. * https://mntre.com
  9. *
  10. * More Info: https://mntre.com/zz9000
  11. *
  12. * SPDX-License-Identifier: GPL-3.0-or-later
  13. * GNU General Public License v3.0 or later
  14. *
  15. * https://spdx.org/licenses/GPL-3.0-or-later.html
  16. *
  17. */
  18. module video_formatter(
  19. input [31:0] m_axis_vid_tdata,
  20. input m_axis_vid_tlast,
  21. output m_axis_vid_tready,
  22. input [0:0] m_axis_vid_tuser,
  23. input m_axis_vid_tvalid,
  24. input m_axis_vid_aclk,
  25. input aresetn,
  26. input dvi_clk,
  27. output reg dvi_hsync,
  28. output reg dvi_vsync,
  29. output reg dvi_active_video,
  30. output reg [31:0] dvi_rgb,
  31. // control inputs for setting palette, width/height, scaling
  32. input [31:0] control_data,
  33. input [7:0] control_op,
  34. input control_interlace,
  35. output reg control_vblank
  36. );
  37. localparam OP_COLORMODE=1;
  38. localparam OP_DIMENSIONS=2;
  39. localparam OP_PALETTE=3;
  40. localparam OP_SCALE=4;
  41. localparam OP_VSYNC=5;
  42. localparam OP_MAX=6;
  43. localparam OP_HS=7;
  44. localparam OP_VS=8;
  45. localparam OP_THRESH=9;
  46. localparam OP_POLARITY=10;
  47. localparam OP_RESET=11;
  48. localparam OP_UNUSED1=12;
  49. localparam OP_SPRITEXY=13;
  50. localparam OP_SPRITE_ADDR=14;
  51. localparam OP_SPRITE_DATA=15;
  52. localparam OP_VIDEOCAP=16; // we ignore this here, it's snooped by MNTZorro
  53. localparam CMODE_8BIT=0;
  54. localparam CMODE_16BIT=1;
  55. localparam CMODE_32BIT=2;
  56. localparam CMODE_15BIT=4;
  57. reg [11:0] screen_width; // = 720;
  58. reg [11:0] screen_height; // = 576;
  59. reg scale_x = 0;
  60. reg scale_y = 1; // amiga boots in 640x256, so double the resolution vertically
  61. reg [31:0] palette[255:0];
  62. reg [2:0] colormode = CMODE_32BIT;
  63. reg vsync_request;
  64. reg sync_polarity = 1; // negative polarity
  65. reg [15:0] screen_h_max; //= 864;
  66. reg [15:0] screen_v_max; //= 625;
  67. reg [15:0] screen_h_sync_start; //= 732;
  68. reg [15:0] screen_h_sync_end; //= 796;
  69. reg [15:0] screen_v_sync_start; //= 581;
  70. reg [15:0] screen_v_sync_end; //= 586;
  71. localparam MAXWIDTH=1280;
  72. reg [31:0] line_buffer[MAXWIDTH-1:0];
  73. // (input) vdma state
  74. reg [3:0] next_input_state;
  75. reg [11:0] inptr;
  76. reg ready_for_vdma;
  77. assign m_axis_vid_tready = ready_for_vdma;
  78. reg [11:0] counter_x; // vga domain
  79. reg [11:0] counter_y; // vga domain
  80. reg [11:0] need_line_fetch; // vga domain
  81. reg [11:0] need_line_fetch_reg;
  82. reg [11:0] need_line_fetch_reg2;
  83. reg [11:0] need_line_fetch_reg3;
  84. reg [11:0] last_line_fetch;
  85. wire [31:0] pixin = m_axis_vid_tdata;
  86. wire pixin_valid = m_axis_vid_tvalid;
  87. wire pixin_end_of_line = m_axis_vid_tlast;
  88. wire pixin_framestart = m_axis_vid_tuser[0];
  89. reg scale_y_effective;
  90. reg need_frame_sync; // vga domain
  91. reg need_frame_sync_reg; // fetch domain
  92. // sprite
  93. localparam SPRITE_W = 32;
  94. localparam SPRITE_H = 48;
  95. localparam SPRITE_SIZE = SPRITE_W*SPRITE_H;
  96. reg [23:0] sprite_buffer[SPRITE_SIZE-1:0];
  97. reg [11:0] sprite_addr_in;
  98. reg [11:0] sprite_x;
  99. reg [11:0] sprite_y;
  100. reg sprite_dbl;
  101. reg vga_sprite_dbl; // vga_domain
  102. reg [11:0] vga_sprite_x; // vga domain
  103. reg [11:0] vga_sprite_y; // vga domain
  104. reg [11:0] vga_sprite_x2; // vga domain
  105. reg [11:0] vga_sprite_y2; // vga domain
  106. reg [11:0] sprite_px; // vga domain
  107. reg [11:0] sprite_py; // vga domain
  108. reg [23:0] sprite_pix; // vga domain
  109. reg sprite_on; // vga domain
  110. always @(posedge m_axis_vid_aclk)
  111. begin
  112. if (~aresetn) begin
  113. ready_for_vdma <= 0;
  114. next_input_state <= 0;
  115. inptr <= 0;
  116. end
  117. need_frame_sync_reg <= need_frame_sync;
  118. need_line_fetch_reg <= need_line_fetch; // sync to clock domain
  119. need_line_fetch_reg2 <= need_line_fetch_reg>>scale_y_effective; // line duplication
  120. scale_y_effective <= control_interlace ? 0 : scale_y;
  121. if (pixin_valid && ready_for_vdma) begin
  122. line_buffer[inptr] <= pixin;
  123. // disabling this makes the picture go wild
  124. if (pixin_framestart) // we might have missed the frame start
  125. inptr <= 1;
  126. else if (pixin_end_of_line) // next after this is the first pixel of the line (0)
  127. inptr <= 0;
  128. else
  129. inptr <= inptr + 1'b1;
  130. end
  131. // one-hot encoded
  132. case (next_input_state)
  133. 4'h0: begin
  134. // wait for start of frame
  135. ready_for_vdma <= 1;
  136. if (pixin_framestart)
  137. next_input_state <= 4'h4;
  138. end
  139. 4'h1: begin
  140. // reading from vdma
  141. last_line_fetch <= need_line_fetch_reg2;
  142. if (pixin_valid && pixin_end_of_line) begin
  143. ready_for_vdma <= 0;
  144. next_input_state <= 4'h2;
  145. end else
  146. ready_for_vdma <= 1; // moved here
  147. end
  148. 4'h2: begin
  149. // we've read more than enough of this line, wait until it's time for the next
  150. if (vsync_request) begin
  151. next_input_state <= 4'h0;
  152. end
  153. else if (need_line_fetch_reg2!=last_line_fetch) begin
  154. // time to read the next line
  155. next_input_state <= 4'h1;
  156. //ready_for_vdma <= 1; // from here
  157. end
  158. end
  159. 4'h4: begin
  160. // we are at frame start, wait for the first line of video output
  161. ready_for_vdma <= 0;
  162. // line_fetch_reg2 == 0
  163. if (need_frame_sync_reg==1) begin
  164. next_input_state <= 4'h2;
  165. end
  166. end
  167. endcase
  168. end
  169. reg [31:0] control_data_in;
  170. reg [7:0] control_op_in;
  171. reg control_interlace_in;
  172. reg [31:0] control_data_in2;
  173. reg [7:0] control_op_in2;
  174. reg control_interlace_in2;
  175. // control input
  176. always @(posedge m_axis_vid_aclk)
  177. begin
  178. control_op_in <= control_op;
  179. control_data_in <= control_data;
  180. control_interlace_in <= control_interlace;
  181. if (next_input_state==0) begin
  182. vsync_request <= 0;
  183. end
  184. if (control_interlace_in != control_interlace) begin
  185. vsync_request <= 1;
  186. end
  187. case (control_op_in)
  188. OP_PALETTE: palette[control_data_in[31:24]] <= control_data_in[23:0];
  189. OP_DIMENSIONS: begin
  190. screen_height <= control_data_in[31:16];
  191. screen_width <= control_data_in[15:0];
  192. end
  193. OP_SCALE: begin
  194. scale_x <= control_data_in[0];
  195. scale_y <= control_data_in[1];
  196. sprite_dbl <= control_data_in[1];
  197. end
  198. OP_COLORMODE: colormode <= control_data_in[1:0]; // FIXME
  199. OP_VSYNC: vsync_request <= 1; //control_data[0];
  200. OP_MAX: begin
  201. screen_v_max <= control_data_in[31:16];
  202. screen_h_max <= control_data_in[15:0];
  203. end
  204. OP_HS: begin
  205. screen_h_sync_start <= control_data_in[31:16];
  206. screen_h_sync_end <= control_data_in[15:0];
  207. end
  208. OP_VS: begin
  209. screen_v_sync_start <= control_data_in[31:16];
  210. screen_v_sync_end <= control_data_in[15:0];
  211. end
  212. OP_THRESH: begin
  213. end
  214. OP_POLARITY: begin
  215. sync_polarity <= control_data_in[0];
  216. end
  217. OP_RESET: begin
  218. sync_polarity <= 1;
  219. screen_h_max <= 864;
  220. screen_v_max <= 625;
  221. screen_h_sync_start <= 732;
  222. screen_h_sync_end <= 796;
  223. screen_v_sync_start <= 581;
  224. screen_v_sync_end <= 586;
  225. scale_x <= 0;
  226. scale_y <= 1;
  227. screen_width <= 720;
  228. screen_height <= 576;
  229. colormode <= CMODE_32BIT;
  230. end
  231. OP_SPRITEXY: begin
  232. sprite_y <= control_data_in[31:16];
  233. sprite_x <= control_data_in[15:0];
  234. end
  235. OP_SPRITE_ADDR: begin
  236. sprite_addr_in <= control_data_in[11:0];
  237. end
  238. OP_SPRITE_DATA: begin
  239. sprite_buffer[sprite_addr_in] <= control_data_in[23:0];
  240. end
  241. endcase
  242. end
  243. reg [31:0] palout;
  244. reg [11:0] vga_v_rez;
  245. reg [11:0] vga_h_rez;
  246. reg [11:0] vga_v_max;
  247. reg [11:0] vga_h_max;
  248. reg [11:0] vga_h_sync_start;
  249. reg [11:0] vga_h_sync_end;
  250. reg [11:0] vga_v_sync_start;
  251. reg [11:0] vga_v_sync_end;
  252. reg [11:0] counter_scanout;
  253. reg [2:0] vga_colormode;
  254. reg [11:0] vga_h_rez_shifted;
  255. reg [11:0] vga_v_rez_shifted;
  256. reg vga_scale_x = 0;
  257. reg [31:0] pixout;
  258. reg [7:0] pixout8;
  259. reg [15:0] pixout16;
  260. reg [31:0] pixout32;
  261. reg [31:0] pixout32_dly;
  262. reg [31:0] pixout32_dly2;
  263. wire [7:0] red16 = {pixout16[4:0], pixout16[4:2]};
  264. wire [7:0] green16 = {pixout16[10:5], pixout16[10:9]};
  265. wire [7:0] blue16 = {pixout16[15:11], pixout16[15:13]};
  266. wire [7:0] red15 = {pixout16[4:0], pixout16[4:2]};
  267. wire [7:0] green15 = {pixout16[9:5], pixout16[9:7]};
  268. wire [7:0] blue15 = {pixout16[14:10], pixout16[14:12]};
  269. reg [3:0] counter_scanout_step;
  270. reg [3:0] counter_subpixel = 0;
  271. reg vga_sync_polarity = 0;
  272. always @(posedge dvi_clk) begin
  273. vga_h_rez <= screen_width;
  274. vga_v_rez <= screen_height;
  275. vga_h_max <= screen_h_max;
  276. vga_v_max <= screen_v_max;
  277. vga_h_sync_start <= screen_h_sync_start; // + 4
  278. vga_h_sync_end <= screen_h_sync_end; // + 4
  279. vga_v_sync_start <= screen_v_sync_start;
  280. vga_v_sync_end <= screen_v_sync_end;
  281. vga_scale_x <= scale_x;
  282. vga_colormode <= colormode;
  283. vga_sync_polarity <= sync_polarity;
  284. if (counter_y == 0) begin
  285. vga_sprite_x <= sprite_x;
  286. vga_sprite_y <= sprite_y;
  287. end
  288. vga_sprite_x2 <= vga_sprite_x+(SPRITE_W<<sprite_dbl);
  289. vga_sprite_y2 <= vga_sprite_y+(SPRITE_H<<sprite_dbl);
  290. vga_sprite_dbl <= sprite_dbl;
  291. // FIXME there is some non-determinism in the relationship
  292. // between this process and the fetching process
  293. // depending on when a new screen is launched, there can be
  294. // 1 row of wrap-around
  295. /*
  296. pipelines (4 clocks):
  297. linebuf pixout32 pixout32_dly pixout32_dly2 pixout
  298. linebuf pixout32 pixout16 pixout32_dly pixout
  299. linebuf pixout32 pixout8 palout pixout
  300. */
  301. case ({vga_scale_x,counter_subpixel[2:0]})
  302. 4'b0011: pixout8 <= pixout32[31:24];
  303. 4'b0000: pixout8 <= pixout32[23:16];
  304. 4'b0001: pixout8 <= pixout32[15:8];
  305. 4'b0010: pixout8 <= pixout32[7:0];
  306. 4'b1111: pixout8 <= pixout32[31:24];
  307. 4'b1000: pixout8 <= pixout32[31:24];
  308. 4'b1001: pixout8 <= pixout32[23:16];
  309. 4'b1010: pixout8 <= pixout32[23:16];
  310. 4'b1011: pixout8 <= pixout32[15:8];
  311. 4'b1100: pixout8 <= pixout32[15:8];
  312. 4'b1101: pixout8 <= pixout32[7:0];
  313. 4'b1110: pixout8 <= pixout32[7:0];
  314. endcase
  315. case ({vga_scale_x,counter_subpixel[1:0]})
  316. 3'b001: pixout16 <= {pixout32[23:16],pixout32[31:24]};
  317. 3'b000: pixout16 <= {pixout32[7:0] ,pixout32[15:8] };
  318. 3'b100: pixout16 <= {pixout32[23:16],pixout32[31:24]};
  319. 3'b111: pixout16 <= {pixout32[23:16],pixout32[31:24]};
  320. 3'b110: pixout16 <= {pixout32[7:0] ,pixout32[15:8] };
  321. 3'b101: pixout16 <= {pixout32[7:0] ,pixout32[15:8] };
  322. endcase
  323. case ({vga_scale_x,vga_colormode})
  324. 4'b0000: counter_scanout_step <= 3; // 8 bit
  325. 4'b1000: counter_scanout_step <= 7;
  326. 4'b0001: counter_scanout_step <= 1; // 16 bit
  327. 4'b1001: counter_scanout_step <= 3;
  328. 4'b0010: counter_scanout_step <= 0; // 32 bit
  329. 4'b1010: counter_scanout_step <= 1;
  330. //4'b0100: counter_scanout_step <= 1; // 15 bit
  331. //4'b1100: counter_scanout_step <= 3;
  332. endcase
  333. if (counter_x>vga_h_rez) begin
  334. counter_scanout <= 0;
  335. counter_subpixel <= counter_scanout_step;
  336. end else begin
  337. if (counter_subpixel == 0) begin
  338. counter_subpixel <= counter_scanout_step;
  339. counter_scanout <= counter_scanout + 1'b1;
  340. end else
  341. counter_subpixel <= counter_subpixel - 1'b1;
  342. end
  343. pixout32 <= line_buffer[counter_scanout];
  344. if (vga_colormode==CMODE_16BIT)
  345. // 16 bit 5r6g5b
  346. pixout32_dly <= {8'b0,blue16,green16,red16};
  347. //else if (vga_colormode==CMODE_15BIT)
  348. // // 15 bit 5r5g5b for shapeshifter
  349. // pixout32_dly <= {8'b0,blue15,green15,red15};
  350. else
  351. pixout32_dly <= pixout32;
  352. pixout32_dly2 <= pixout32_dly;
  353. palout <= palette[pixout8];
  354. case (vga_colormode)
  355. CMODE_8BIT: pixout <= palout;
  356. CMODE_16BIT: pixout <= pixout32_dly;
  357. CMODE_32BIT: pixout <= pixout32_dly2;
  358. endcase
  359. sprite_pix <= sprite_buffer[((sprite_py>>sprite_dbl)<<5)+(sprite_px>>sprite_dbl)];
  360. if (counter_y >= vga_sprite_y && counter_y < vga_sprite_y2
  361. && counter_x >= vga_sprite_x && counter_x < vga_sprite_x2) begin
  362. sprite_on <= 1;
  363. if (sprite_px < (SPRITE_W<<sprite_dbl)-1'b1)
  364. sprite_px <= sprite_px + 1'b1;
  365. else begin
  366. sprite_px <= 0;
  367. sprite_py <= sprite_py + 1'b1;
  368. end
  369. end else begin
  370. sprite_on <= 0;
  371. end
  372. dvi_rgb <= (sprite_on && sprite_pix!='hff00ff) ? sprite_pix : pixout;
  373. if (counter_x > vga_h_max) begin
  374. counter_x <= 0;
  375. if (counter_y > vga_v_max) begin
  376. counter_y <= 0;
  377. sprite_px <= 0;
  378. sprite_py <= 0;
  379. end else begin
  380. counter_y <= counter_y + 1'b1;
  381. end
  382. end else begin
  383. counter_x <= counter_x + 1'b1;
  384. end
  385. if (counter_x==vga_h_rez) begin
  386. if (counter_y<vga_v_rez-1'b1)
  387. need_line_fetch <= counter_y + 1'b1;
  388. else
  389. need_line_fetch <= 0;
  390. end
  391. // signal synchronization point to fetch process
  392. if (counter_x<8 && counter_y==vga_v_sync_start)
  393. need_frame_sync <= 1;
  394. else
  395. need_frame_sync <= 0;
  396. if (counter_x>=vga_h_sync_start && counter_x<vga_h_sync_end)
  397. dvi_hsync <= 1^vga_sync_polarity;
  398. else
  399. dvi_hsync <= 0^vga_sync_polarity;
  400. if (counter_y>=vga_v_sync_start && counter_y<vga_v_sync_end) begin
  401. dvi_vsync <= 1^vga_sync_polarity;
  402. control_vblank <= 1;
  403. end
  404. else begin
  405. dvi_vsync <= 0^vga_sync_polarity;
  406. control_vblank <= 0;
  407. end
  408. // 4 clocks pipeline delay
  409. vga_h_rez_shifted <= vga_h_rez+4;
  410. if (counter_y<vga_v_rez && counter_x==4)
  411. dvi_active_video <= 1;
  412. if (counter_x==vga_h_rez_shifted)
  413. dvi_active_video <= 0;
  414. end
  415. endmodule