/* */ /* PC-6001mkII VGA Adapter with sprite extension */ /* */ /* (C) Koichi Nishida */ /* */ /* May 12, 2016 */ /* All Rights Reserved */ /* */ /* reads data from line buffers and output video signal on the VGA port */ /* and also generates timing for p6_scan and make_sprite_line process */ process out_vga( clkin uint#1 clk, rstin uint#1 rst, in uint#1 hsync, // VGA hsync input out uint#4 latch ro, // 4 bit RGB outputs out uint#4 latch go, out uint#4 latch bo, ram uint#4 p6_line_buff[4096], // line buffer memory for P6 screen ram uint#4 sprite_line_buff[4096], // line buffer memory for sprite out uint#8 latch scan_y, // scan line number for the next scanning out uint#1 latch start, // start signal for make_sprite_line out uint#1 latch line_buf_offset, // when this is 1, higher address should be used for the p6_line_buff and sprite_line_buff. // this value toggles at every scan line in uint#9 scroll, // scroll value out uint#1 latch busy, // 1 when actual display task is processing. in uint#1 mode, // 0:mkII screen mode, 1: original P6 screen mode in uint#16 priority, // priorities between sprites and P6 screen for each color in uint#1 p6off, in uint#5 left_cut, in uint#5 right_cut ) { uint#5 left_cut_s = left_cut; uint#5 right_cut_s = right_cut; uint#1 mode_s = mode; uint#9 width = (mode_s?256:320); uint#9 width_cut = width-right_cut_s; uint#9 scr = (mode_s?scroll#(8..1):scroll); uint#16 priority_s = priority; uint#1 p6off_s = p6off; start = 0; ro = 0; go = 0; bo = 0; { uint#6 i; for (i=0; i!=28; i++) { wait; while (hsync) ; wait; while (!hsync) ; } } { uint#1 _ramsel = 1; uint#9 i; for (i=0; i!=240;i++) { uint#1 valid_area; uint#2 h; if (mode) { valid_area = ((i >= 17+4) && (i < 217-4)); } else { valid_area = ((i >= 17) && (i < 217)); } start = 0; for (h=0; h!=2; h++) { while (hsync) ; wait; busy = valid_area; while (!hsync) ; // even line { // back porch uint#7 j; for (j=0; j != (mode_s?((uint#7)39+64):39); j++) ; } { // visible area uint#9 j, k; uint#12 d = 0; uint#4 q = 0; uint#1 prio_graph = 0; for (j=0, k=16; j != (width_cut+1); j++, k++) { // decode 16 colors uint#1 r, g, b, c; uint#1 cut = (j < (uint#9)left_cut_s); if (p6off_s) d = 0; if (d == 0) { prio_graph = priority_s#(0); } else if (d == 1) { prio_graph = priority_s#(1); } else if (d == 2) { prio_graph = priority_s#(2); } else if (d == 3) { prio_graph = priority_s#(3); } else if (d == 4) { prio_graph = priority_s#(4); } else if (d == 5) { prio_graph = priority_s#(5); } else if (d == 6) { prio_graph = priority_s#(6); } else if (d == 7) { prio_graph = priority_s#(7); } else if (d == 8) { prio_graph = priority_s#(8); } else if (d == 9) { prio_graph = priority_s#(9); } else if (d == 10) { prio_graph = priority_s#(10); } else if (d == 11) { prio_graph = priority_s#(11); } else if (d == 12) { prio_graph = priority_s#(12); } else if (d == 13) { prio_graph = priority_s#(13); } else if (d == 14) { prio_graph = priority_s#(14); } else { prio_graph = priority_s#(15); } if (prio_graph) { if (d!=0) { r = d#(1), g = d#(2), b = d#(0), c = d#(3); } else { r = q#(1), g = q#(2), b = q#(0), c = q#(3); } } else { if (q!=0) { r = q#(1), g = q#(2), b = q#(0), c = q#(3); } else { r = d#(1), g = d#(2), b = d#(0), c = d#(3); } } wait; if (!valid_area) { ro = 0; go = 0; bo = 0; } else { uint#12 s = (((~(c|~((r&g)|(~(r|g)&b))))?0b1000:(r@r@r@r)) @ ((~(c|~((g&b)|(~(g|b)&r))))?0b1000:(g@g@g@g)) @ ((~(c|~((r&b)|(~(r|b)&g))))?0b1000:(b@b@b@b))); ro = s#(11..8); go = s#(7..4); bo = s#(3..0); } { uint#10 l = (uint#10)j+scr; if (cut) { d = 0; q = 0; } else { if (l>=width) l-=width; d = p6_line_buff[_ramsel@(uint#10)l]; q = sprite_line_buff[_ramsel@(uint#10)k]; } } } ro = 0; go = 0; bo = 0; } } scan_y = i+1; line_buf_offset = _ramsel; start = 1; _ramsel = !_ramsel; } } while (1) ; } /* scan P6 screen line */ process p6_scan( clkin uint#1 clk, rstin uint#1 rst, in uint#1 rin, // RGBC input from P6mkII in uint#1 gin, in uint#1 bin, in uint#1 cin, ram uint#4 p6_line_buff[4096], // line buffer memory // in uint#8 pd, // for displaying debug data in uint#1 line_buf_offset, // when this is 1, higher address is used for the p6_line_buff. in uint#3 sw, // for calibration in uint#1 mode // 0:mkII screen mode, 1: original P6 screen mode ) { { // front porch uint#10 j; uint#10 k = (mode?(519+256+sw):(519+sw)); for (j=0; j != k; j++) ; } { uint#10 j; uint#1 line_buf_offset_s = line_buf_offset; uint#9 width = (mode?(uint#9)256:(uint#9)320); for (j = 0; j != width; j++) { uint#4 d; /* for displaying debug data uint#10 k = (j>>2); if (k==32) { d = ((pd&0b10000000)?0xf:1); } else if (k==34) { d = ((pd&0b01000000)?0xf:1); } else if (k==36) { d = ((pd&0b00100000)?0xf:1); } else if (k==38) { d = ((pd&0b00010000)?0xf:1); } else if (k==40) { d = ((pd&0b00001000)?0xf:1); } else if (k==42) { d = ((pd&0b00000100)?0xf:1); } else if (k==44) { d = ((pd&0b00000010)?0xf:1); } else if (k==46) { d = ((pd&0b00000001)?0xf:1); } else */ { d = cin@gin@rin@bin; } wait; p6_line_buff[line_buf_offset_s@j]=d; wait; wait; wait; wait; wait; wait; } } while (1) ; } /* make 1/19 clock */ process div19 ( clkin uint#1 clk, rstin uint#1 rst, in uint#1 hin, // horizontal sync from P6mkII is used for adjusting phase out uint#1 latch outp ) { uint#5 ctr = 0; uint#1 prev = 0; while (1) { //int#1 hin_s = hin; //if (prev & !hin_s) ctr=0; if (++ctr == 19) { ctr = 0; outp = 0; } else if (ctr == 9) { outp = 1; } //prev = hin_s; } } /* component declaration for Digital Clock Manager in the FPGA */ /* see the Spartan 3A manual for the detail */ component DCM_SP( out uint#1 CLKFX, in uint#1 CLKIN, in uint#1 PSCLK, in uint#1 PSEN, in uint#1 PSINCDEC, in uint#1 RST, out uint#1 LOCKED ); component BUFG(in uint#1 I, out uint#1 O); /* generate VGA horizontal sync */ process gen_hsync( clkin uint#1 clk, rstin uint#1 rst, in uint#1 hin, // P6mkII's hsync in uint#1 vin, out uint#1 latch hsync ) { uint#10 ctr = 0; uint#1 prevv = 0, prevh = 0, valid = 0; while (1) { uint#1 hsy = hin, vsy = vin; if (++ctr == /*456*/800) ctr = 0; if (prevh & !hsy & valid) { ctr = 0; valid = 0; } if (prevv & !vsy & !valid) valid = 1; prevv = vsy; prevh = hsy; if (ctr == 0) hsync = 0; else if (ctr == /*54*/96) hsync = 1; } } /* generate VGA vertical sync */ process gen_vsync( clkin uint#1 clk, rstin uint#1 rst, in uint#1 hin, // P6mkII's hsync out uint#1 latch vsync ) { while (!hin) ; vsync = 1; wait; while (hin) ; wait; while (!hin) ; vsync = 0; while (1) ; } /* make sprite line buffer data */ process make_sprite_line( clkin uint#1 clk, rstin uint#1 rst, in uint#8 line_y, // horizontal line to process in uint#1 line_buf_offset, // when this is 1, higher address is used for the sprite_line_buff. ram uint#4 sprite_line_buff[4096], // line buffer ram uint#9 sprite_attr_buff[2048], // attribute buffer ram uint#4 sprite_chr_buff0[4096], // character buffers ram uint#4 sprite_chr_buff1[4096], ram uint#4 sprite_chr_buff2[4096], ram uint#4 sprite_chr_buff3[4096], ram uint#4 sprite_chr_buff4[4096], ram uint#4 sprite_chr_buff5[4096], ram uint#4 sprite_chr_buff6[4096], ram uint#4 sprite_chr_buff7[4096], ram uint#4 sprite_chr_buff8[4096], ram uint#4 sprite_chr_buff9[4096], ram uint#4 sprite_chr_buff10[4096], ram uint#4 sprite_chr_buff11[4096], in uint#1 mode // 0:mkII screen mode, 1: original P6 screen mode ) { uint#1 line_buf_offset_s; wait; wait; wait; line_buf_offset_s = line_buf_offset; { // clear line buffer uint#9 i; for (i=0; i!=338; i++) { sprite_line_buff[line_buf_offset_s@(uint#10)i] = 0; } } { uint#9 i; uint#6 count = 0; // a counter to limit 20 sprites for the horizontal line for (i=255; (i != 0b111111111) && (count != 20); i--) { uint#9 sp_attr = sprite_attr_buff[i@0b000]; // attr: base address + 0 uint#1 display = (sp_attr#(0)); // attr bit 0 : whether display the sprite or not if (!display) continue; { uint#9 sp_y = sprite_attr_buff[i@0b010]; // y: base address + 2 uint#8 line_ys = line_y; uint#8 linked_sp = sprite_attr_buff[i@0b100]; // link sprite: base address + 4 if (mode) sp_y += 4; if (sp_attr#(4)) { // attr bit 4: whether link or not sp_y += sprite_attr_buff[linked_sp@0b010]; // add y of the linked sprite } // attr bit 5: 8x8 size sprite if (!(((sp_y+(sp_attr#(5)?7:15)) >= line_ys) && (sp_y <= line_ys))) continue; { uint#8 chr_num = sprite_attr_buff[i@0b011]; // character pattern number: base address + 3 uint#16 sp_buff_adr; uint#12 sp_buff_adr_sub; uint#4 sp_buff_num; uint#5 j; uint#10 sp_x; uint#9 line_adr; uint#1 at7 = (sp_attr#(3)?sp_attr#(6):sp_attr#(7)); uint#1 at6 = (sp_attr#(3)?sp_attr#(7):sp_attr#(6)); uint#4 ysp = (line_ys-sp_y) + ((at7&sp_attr#(5))?8:0); // attr bit 7: Y pattern offset for 8x8 size uint#4 ysp7_15 = (sp_attr#(5)?7:15)-(line_ys-sp_y)+((at7&sp_attr#(5))?8:0); uint#4 xofs = ((at6&sp_attr#(5))?0b1000:0b0000); // attr bit 6: X pattern offset for 8x8 size if (sp_attr#(2)) { // attr bit 2: flip vertically or not if (sp_attr#(3)) { // attr bit 3: rotate counterclockwise 90 degree or not sp_buff_adr = chr_num@xofs@ysp; // rotate counterclockwise 90 degree + vertical flip } else { sp_buff_adr = chr_num@ysp7_15@xofs; // flip vertically } } else { if (sp_attr#(3)) { sp_buff_adr = chr_num@xofs@ysp7_15; // rotate counterclockwise 90 degree } else { sp_buff_adr = chr_num@ysp@xofs; // normal } } sp_buff_adr_sub = sp_buff_adr; // address in a chr buffer memory sp_buff_num = sp_buff_adr#(15..12); // which chr memory is used sp_x = sprite_attr_buff[i@0b001]; // x: base address + 1 if (sp_attr#(4)) { // attr bit 4: whether link or not sp_x += sprite_attr_buff[linked_sp@0b001]; // add x of the linked sprite } line_adr = sp_x+(sp_attr#(1)?(sp_attr#(5)?7:15):0); // attr bit 1: flip horizontally or not count++; for (j=0; j!=(sp_attr#(5)?8:16); j++) { uint#4 chr_data0 = sprite_chr_buff0[sp_buff_adr_sub]; // read chr data uint#4 chr_data1 = sprite_chr_buff1[sp_buff_adr_sub]; uint#4 chr_data2 = sprite_chr_buff2[sp_buff_adr_sub]; uint#4 chr_data3 = sprite_chr_buff3[sp_buff_adr_sub]; uint#4 chr_data4 = sprite_chr_buff4[sp_buff_adr_sub]; uint#4 chr_data5 = sprite_chr_buff5[sp_buff_adr_sub]; uint#4 chr_data6 = sprite_chr_buff6[sp_buff_adr_sub]; uint#4 chr_data7 = sprite_chr_buff7[sp_buff_adr_sub]; uint#4 chr_data8 = sprite_chr_buff8[sp_buff_adr_sub]; uint#4 chr_data9 = sprite_chr_buff9[sp_buff_adr_sub]; uint#4 chr_data10 = sprite_chr_buff10[sp_buff_adr_sub]; uint#4 chr_data11 = sprite_chr_buff11[sp_buff_adr_sub]; uint#4 chr_data = 0; if (sp_buff_num == 0) { chr_data = chr_data0; } else if (sp_buff_num == 1) { chr_data = chr_data1; } else if (sp_buff_num == 2) { chr_data = chr_data2; } else if (sp_buff_num == 3) { chr_data = chr_data3; } else if (sp_buff_num == 4) { chr_data = chr_data4; } else if (sp_buff_num == 5) { chr_data = chr_data5; } else if (sp_buff_num == 6) { chr_data = chr_data6; } else if (sp_buff_num == 7) { chr_data = chr_data7; } else if (sp_buff_num == 8) { chr_data = chr_data8; } else if (sp_buff_num == 9) { chr_data = chr_data9; } else if (sp_buff_num == 10) { chr_data = chr_data10; } else if (sp_buff_num == 11) { chr_data = chr_data11; } if (sp_attr#(3)) { // attr bit 3: rotate counterclockwise 90 degree or not sp_buff_adr_sub+=16; } else { sp_buff_adr_sub++; } if (chr_data!=0) { // if not transparent, write to the line buffer sprite_line_buff[line_buf_offset_s@(uint#10)line_adr] = chr_data; } if (sp_attr#(1)) line_adr--; else line_adr++; // attr bit 1: flip horizontally or not } } } } } while (1) ; } /* double buffering the attribute buffer */ process copy_attr_buff( clkin uint#1 clk, rstin uint#1 rst, ram uint#9 sprite_attr_buff_in[2048], ram uint#9 sprite_attr_buff_out[2048] ) { uint#12 i; for (i=0; i!=2048; i++) { uint#9 d = sprite_attr_buff_in[i]; wait; sprite_attr_buff_out[i] = d; } while (1) ; } /* receive command from P6mkII's printer port and execute */ process receive_command( clkin uint#1 clk, rstin uint#1 rst, stateout uint#8 ctrl_state, // for debug in uint#1 pstrobe, // strobe signal from P6mkII in uint#8 pd, // data from P6mkII ram uint#9 sprite_attr_buff[2048], // ram uint#4 sprite_chr_buff0[4096], ram uint#4 sprite_chr_buff1[4096], ram uint#4 sprite_chr_buff2[4096], ram uint#4 sprite_chr_buff3[4096], ram uint#4 sprite_chr_buff4[4096], ram uint#4 sprite_chr_buff5[4096], ram uint#4 sprite_chr_buff6[4096], ram uint#4 sprite_chr_buff7[4096], ram uint#4 sprite_chr_buff8[4096], ram uint#4 sprite_chr_buff9[4096], ram uint#4 sprite_chr_buff10[4096], ram uint#4 sprite_chr_buff11[4096], out uint#9 latch scroll, out uint#1 latch mode, out uint#16 latch priority, out uint#1 latch p6off, out uint#5 latch left_cut, out uint#5 latch right_cut, out uint#1 latch led ) { uint#9 scroll_reg = 0; uint#16 priority_reg = 0; /* test program uint#9 y; uint#9 i = 0; uint#3 attr = 0; for (y=0; y!=#(16*16); y+=16) { uint#9 x; for (x=0; x!=#(16*16); x+=16) { sprite_attr_buff[i@0b000] = (((i==0x00)?0b0:0b1)@attr@1); sprite_attr_buff[i@0b000+1] = ((i==0x00)?16:x); sprite_attr_buff[i@0b000+2] = ((i==0x00)?16:y); sprite_attr_buff[i@0b000+3] = ((i&1)?160:0); sprite_attr_buff[i@0b000+4] = 0; i++; if (i==256) break; if (i&1) attr++; } if (i==256) break; } */ { uint#8 target_num = 0; while (1) { led = 1; while (pstrobe) ; // wait first byte { uint#8 first_byte = pd; led = 0; while (!pstrobe) ; // wait second byte { uint#8 second_byte = pd; wait; { uint#8 param_num = first_byte#(3..0);// param_num : lower 4 bit of the first byte uint#8 command = first_byte#(7..4); // command: higher 4 bit of the first byte if (command == 1) { // set target sprite number target_num = second_byte; } else if (command == 2) { // set sprite attribute if (param_num == 0) { // attribute sprite_attr_buff[target_num@0b000] = second_byte; } else if (param_num == 1) { // x (lower 1 bit) uint#9 prev = sprite_attr_buff[target_num@0b001]; sprite_attr_buff[target_num@0b001] = prev#(8..1) @ second_byte#(0); } else if (param_num == 2) { // x (higher 8 bit) uint#9 prev = sprite_attr_buff[target_num@0b001]; sprite_attr_buff[target_num@0b001] = second_byte @ prev#(0); } else if (param_num == 3) { // y sprite_attr_buff[target_num@0b010] = second_byte; } else if (param_num == 4) { // character pattern num sprite_attr_buff[target_num@0b011] = second_byte; } else if (param_num == 5) { // linked sprite sprite_attr_buff[target_num@0b100] = second_byte; } } else if (command == 3) { // set pattern data uint#16 adrs = second_byte@0b00000000; uint#4 buff_num = adrs#(15..12); uint#12 buff_adr = adrs#(11..0); uint#8 i; for (i=0; i!=128; i++) { if (i#(0)) { wait; while (!pstrobe) ; wait; } else { wait; while (pstrobe) ; wait; } { uint#8 dt = pd; wait; if (buff_num==0) { sprite_chr_buff0[buff_adr++] = dt#(7..4); sprite_chr_buff0[buff_adr++] = dt#(3..0); } else if (buff_num==1) { sprite_chr_buff1[buff_adr++] = dt#(7..4); sprite_chr_buff1[buff_adr++] = dt#(3..0); } else if (buff_num==2) { sprite_chr_buff2[buff_adr++] = dt#(7..4); sprite_chr_buff2[buff_adr++] = dt#(3..0); } else if (buff_num==3) { sprite_chr_buff3[buff_adr++] = dt#(7..4); sprite_chr_buff3[buff_adr++] = dt#(3..0); } else if (buff_num==4) { sprite_chr_buff4[buff_adr++] = dt#(7..4); sprite_chr_buff4[buff_adr++] = dt#(3..0); } else if (buff_num==5) { sprite_chr_buff5[buff_adr++] = dt#(7..4); sprite_chr_buff5[buff_adr++] = dt#(3..0); } else if (buff_num==6) { sprite_chr_buff6[buff_adr++] = dt#(7..4); sprite_chr_buff6[buff_adr++] = dt#(3..0); } else if (buff_num==7) { sprite_chr_buff7[buff_adr++] = dt#(7..4); sprite_chr_buff7[buff_adr++] = dt#(3..0); } else if (buff_num==8) { sprite_chr_buff8[buff_adr++] = dt#(7..4); sprite_chr_buff8[buff_adr++] = dt#(3..0); } else if (buff_num==9) { sprite_chr_buff9[buff_adr++] = dt#(7..4); sprite_chr_buff9[buff_adr++] = dt#(3..0); } else if (buff_num==10) { sprite_chr_buff10[buff_adr++] = dt#(7..4); sprite_chr_buff10[buff_adr++] = dt#(3..0); } else if (buff_num==11) { sprite_chr_buff11[buff_adr++] = dt#(7..4); sprite_chr_buff11[buff_adr++] = dt#(3..0); } } } } else if (command == 4) { // set scroll if (param_num == 0) { // x (lower 1 bit) scroll_reg = scroll_reg#(8..1) @ second_byte#(0); scroll = scroll_reg; } else if (param_num == 1) { // x (higher 8 bit) scroll_reg = second_byte @ scroll_reg#(0); scroll = scroll_reg; } } else if (command == 5) { // mode change if (param_num == 0) mode = 0; else if (param_num == 1) mode = 1; } else if (command == 6) { if (param_num == 0) priority_reg = priority_reg#(15..8)@second_byte; else if (param_num == 1) priority_reg = second_byte@priority_reg#(7..0); priority = priority_reg; } else if (command == 7) { if (param_num == 0) p6off = 0; else if (param_num == 1) p6off = 1; } else if (command == 8) { if (param_num == 0) { left_cut = second_byte; } else if (param_num == 1) { right_cut = second_byte; } } } } } } } } /* top level connection of everything */ toplevel p6mk2vga ( in uint#1 pin<86> clk_in, // 14.318 MHz from P6mkII in uint#1 pin<49> rst, out uint#1 pin<28> led, in uint#1 pin<56> rin, // RGBC from P6mkII in uint#1 pin<57> gin, in uint#1 pin<59> bin, in uint#1 pin<60> cin, in uint#1 pin<50> hin, // H/V sync from P6mkII in uint#1 pin<52> vin, in uint#8 pin<3,4,5,6,9,10,12,13> pd, // data from the printer port in uint#1 pin<90> pstrobe, // strobe from the printer port out uint#1 pin<16> pready, // used to output VBLANK to P6mkII in uint#6 pin<32-37> sw, // switch on the adapter out uint#1 pin<65> hout, // VGA H/V sync out uint#1 pin<64> vout, out uint#4 pin<77,78,83,84> rout, // VGA RGB outputs out uint#4 pin<70,71,72,73> gout, out uint#4 pin<88,89,93,94> bout ) { com uint#1 clk; // for 14.318 MHz com uint#1 clkn, clk_inn; // for inverse of 14.318 MHz com uint#1 clk4x, clk4xo, clk4xlocked; // for 14.318x4 MHz com uint#1 clk19do, clk19d; // for 14.318x4/19 = 3.0143 MHz com uint#1 clk25o, clk25, clk25locked; // for VGA's 25.12 MHz com uint#1 clksp, clkspo, clksplocked; // for sprite, 14.318x3 = 42.954 MHz com uint#1 rstn; com uint#1 zero; com uint#1 hsync, vsync; // H/V sync of VGA com uint#1 hsync25; com uint#8 scan_y; // scan line number for the next scanning com uint#1 start, startn; // start signal for the make_sprite_line com uint#1 line_buf_offset; // when this is 1, higher address should be used for the p6_line_buff and sprite_line_buff com uint#8 pdn; // inverse of data from the printer port com uint#1 vinn; // inverse of vin ram uint#4 port_num<2> clock p6_line_buff[4096]; // p6 screen line buffer ram uint#4 port_num<2> clock sprite_line_buff[4096]; // sprite line buffer ram uint#9 port_num<2> clock sprite_attr_buff_in[2048]; ram uint#9 port_num<2> clock sprite_attr_buff_out[2048]; ram uint#4 port_num<2> clock sprite_chr_buff0[4096]; ram uint#4 port_num<2> clock sprite_chr_buff1[4096]; ram uint#4 port_num<2> clock sprite_chr_buff2[4096]; ram uint#4 port_num<2> clock sprite_chr_buff3[4096]; ram uint#4 port_num<2> clock sprite_chr_buff4[4096]; ram uint#4 port_num<2> clock sprite_chr_buff5[4096]; ram uint#4 port_num<2> clock sprite_chr_buff6[4096]; ram uint#4 port_num<2> clock sprite_chr_buff7[4096]; ram uint#4 port_num<2> clock sprite_chr_buff8[4096]; ram uint#4 port_num<2> clock sprite_chr_buff9[4096]; ram uint#4 port_num<2> clock sprite_chr_buff10[4096]; ram uint#4 port_num<2> clock sprite_chr_buff11[4096]; com uint#3 sw20; // for calibration com uint#9 scroll; // scroll value com uint#1 mode; // 0:mkII screen mode, 1: original P6 screen mode com uint#1 busy, busyn; // 1 when actual display task is processing. com uint#8 stt; com uint#16 priority; // priorities between sprites and P6 screen for each color com uint#1 p6off; com uint#5 left_cut, right_cut; sw20 = sw#(2..0); // SW2..0 is used for calibration busyn = ~busy; pready = busyn; // VBLANK output to P6mkII pdn = ~pd; // data from P6 is inversed zero = 0; rstn = ~rst; // inverse of rst clk_inn = ~clk_in; vinn = ~vin; // inverse of vin BUFG(clk_in, clk); // clock buffer for clk (14.318MHz) BUFG(clk_inn, clkn); // clock buffer for inversed clk BUFG(clk4xo, clk4x); // clock buffer for 14.318x4 MHz div19(clk4xo, rst, hin, clk19do); BUFG(clk19do, clk19d); // clock buffer for 14.318x4/57 = 1.0048 MHz /* This DCM generats 14.318 x 4 MHz */ generic ( CLKDV_DIVIDE => 2.0, CLKFX_DIVIDE => 1, CLKFX_MULTIPLY => 4, CLKIN_DIVIDE_BY_2 => FALSE, CLKIN_PERIOD => 70.0, CLKOUT_PHASE_SHIFT => "NONE", CLK_FEEDBACK => "NONE", DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", DLL_FREQUENCY_MODE => "LOW", DUTY_CYCLE_CORRECTION => FALSE, PHASE_SHIFT => 0, STARTUP_WAIT => FALSE ) DCM_SP(clk4xo, clk, zero, zero, zero, rstn, clk4xlocked); /* This DCM generats 25.12 MHz */ generic ( CLKDV_DIVIDE => 2.0, CLKFX_DIVIDE => 3, CLKFX_MULTIPLY => 25, CLKIN_DIVIDE_BY_2 => FALSE, CLKIN_PERIOD => 500.0, CLKOUT_PHASE_SHIFT => "NONE", CLK_FEEDBACK => "NONE", DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", DLL_FREQUENCY_MODE => "LOW", DUTY_CYCLE_CORRECTION => FALSE, PHASE_SHIFT => 0, STARTUP_WAIT => FALSE ) DCM_SP(clk25o, clk19d, zero, zero, zero, rstn, clk25locked); BUFG(clk25o, clk25); /* This DCM generats 14.318x3 = 42.954 MHz */ generic ( CLKDV_DIVIDE => 2.0, CLKFX_DIVIDE => 1, CLKFX_MULTIPLY => 3, CLKIN_DIVIDE_BY_2 => FALSE, CLKIN_PERIOD => 70.0, CLKOUT_PHASE_SHIFT => "NONE", CLK_FEEDBACK => "NONE", DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", DLL_FREQUENCY_MODE => "LOW", DUTY_CYCLE_CORRECTION => FALSE, PHASE_SHIFT => 0, STARTUP_WAIT => FALSE ) DCM_SP(clkspo, clk, zero, zero, zero, rstn, clksplocked); BUFG(clkspo, clksp); startn = ~start; /* make sprite line buffer data */ make_sprite_line(clksp, startn, scan_y, line_buf_offset, sprite_line_buff port<0>, sprite_attr_buff_out port<0>, sprite_chr_buff0 port<0>, sprite_chr_buff1 port<0>, sprite_chr_buff2 port<0>, sprite_chr_buff3 port<0>, sprite_chr_buff4 port<0>, sprite_chr_buff5 port<0>, sprite_chr_buff6 port<0>, sprite_chr_buff7 port<0>, sprite_chr_buff8 port<0>, sprite_chr_buff9 port<0>, sprite_chr_buff10 port<0>, sprite_chr_buff11 port<0>, mode ); /* scan P6 screen line */ p6_scan(clk4x, hin, rin, gin, bin, cin, p6_line_buff port<0>, /*pdn stt,*/ line_buf_offset, sw20, mode); /* reads data from line buffers and output video signal on the VGA port */ /* and also generates timing for p6_scan and make_sprite_line process */ out_vga(clk25, vin, hsync/*25*/, rout, gout, bout, p6_line_buff port<1>, sprite_line_buff port<1>, scan_y, start, line_buf_offset, scroll, busy, mode, priority, p6off, left_cut, right_cut); /* generate V sync of VGA */ gen_hsync(clk25, clk25locked, hin, vin, hsync); hout = hsync; /* generate V sync of VGA */ gen_vsync(clk, vinn, hin, vsync); vout= ~vsync; /* double buffering the attribute buffer */ copy_attr_buff( clk4x, busyn, sprite_attr_buff_in port<0>, sprite_attr_buff_out port<1> ); /* receive command from P6mkII's printer port and execute */ receive_command(clksp, rst, stt, pstrobe, pdn, sprite_attr_buff_in port<1>, sprite_chr_buff0 port<1>, sprite_chr_buff1 port<1>, sprite_chr_buff2 port<1>, sprite_chr_buff3 port<1>, sprite_chr_buff4 port<1>, sprite_chr_buff5 port<1>, sprite_chr_buff6 port<1>, sprite_chr_buff7 port<1>, sprite_chr_buff8 port<1>, sprite_chr_buff9 port<1>, sprite_chr_buff10 port<1>, sprite_chr_buff11 port<1>, scroll, mode, priority, p6off, left_cut, right_cut, led ); }