Firmware for MNT ZZ9000 graphics and ARM coprocessor card for Amiga computers.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

474 lines
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