Ok, here we go, get the attached project.
It is your responsibility to document and update the revision numbers....
First big change, the drawing functions have been updated to these new ones:
Once the triangle fills, you will need to edit the command numbers. We will want these commands:
0 = do nothing.
1 = place a pixel. (Currently a line, or the triangle we are debugging.)
2 = draw a line.
3 = draw a triangle.
4 = draw a box
5 = draw a quadrilateral
6 = draw an ellipse
7 = draw a Bezier Curve (spare, may be used for something else).
Fills have yet to be done.
Changes in line_generator.sv:
1. 'line_complete' is now a single 1-shot after the line is finished.
Enabling line 58 in the code and disabling the other instances in the code changes 'line_complete' into a 1-shot which is send during the final pixel output, meaning you shave 1 clock off when stringing one line command to the next in a sequence. However, the FMAX will drop below 125MHz in the current setup.
2. 'ypos_stopped' now switches off immediately as the 'ena_stop_y' input goes low, IE it's now combinational logic saving a clock cycle.
3. Numerous other logic start and stop bugs cleaned up.
Changes in geometry_xy_plotter.sv:
1. New line setup Look Up Tables. (LUT seem to slow down simulation by a big factor since I use large ones...Sorry)
A) This lookup table counts the number of sequences each linegen needs to run: 167-183
// This lookup table specifies the number of sequence cycles each linegen needs to run before completing the final shape
logic [2:0] LUT_LG_CMD_SEQ_SIZE[0:31] = '{ // Linegen 1, Linegen 2 sequence size
0,0, // Shape 0 = NOTHING
1,0, // Shape 1 = Pixel
1,0, // Shape 2 = Line
1,2, // Shape 3 = Triangle
4,0, // Shape 4 = Box
4,0, // Shape 5 = Quadrilateral
0,0, // Shape 6 = Ellipse
0,0, // Shape 7 = Bezier Curve
0,0, // Shape f0 = NOTHING
0,0, // Shape f1 = Pixel
0,0, // Shape f2 = Line
0,0, // Shape f3 = Triangle Filled
0,0, // Shape f4 = Box Filled
0,0, // Shape f5 = Quadrilateral Filled
0,0, // Shape f6 = Ellipse Filled
0,0 }; // Shape f7 = Bezier Curve Filled
B) These 2 lookup tables tells which XY coordinates to use during each linegen sequence: 185-220
// These are the lookup tables to select which X/Y source for A,B
// The order is stage 0A,0B, 1A,1B, 2A,2B, 3A,3B, 4A,4B, 5A,5B, 6A,6B, 7A,7B
logic [1:0] LUT_LG1_SEL_XY[0:511] = '{
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 0 = NOTHING
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 1 = Pixel
0,0,1,1, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 2 = Line
0,0,2,2, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 3 = Triangle
0,0,1,0, 1,0,1,1, 1,1,0,1, 0,1,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 4 = Box
0,0,1,1, 1,1,2,2, 2,2,3,3, 3,3,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 5 = Quadrilateral
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 6 = Ellipse
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 7 = Bezier Curve
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f0 = NOTHING
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f1 = Pixel
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f2 = Line
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f3 = Triangle Filled
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f4 = Box Filled
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f5 = Quadrilateral Filled
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f6 = Ellipse Filled
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; // Shape f7 = Bezier Curve Filled
logic [1:0] LUT_LG2_SEL_XY[0:511] = '{
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 0 = NOTHING
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 1 = Pixel
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 2 = Line
0,0,1,1, 1,1,2,2, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 3 = Triangle
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 4 = Box
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 5 = Quadrilateral
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 6 = Ellipse
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape 7 = Bezier Curve
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f0 = NOTHING
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f1 = Pixel
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f2 = Line
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f3 = Triangle Filled
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f4 = Box Filled
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f5 = Quadrilateral Filled
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // Shape f6 = Ellipse Filled
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; // Shape f7 = Bezier Curve Filled
These variables hold each linegen sequence position: 159-164
logic [2:0] lg1_seq ; // Sequence counter for geometric shapes with multiple lines
logic [2:0] lg2_seq ; // Sequence counter for geometric shapes with multiple lines
logic [2:0] lg1_seq_end ; // Sequence counter for geometric shapes with multiple lines
logic [2:0] lg2_seq_end ; // Sequence counter for geometric shapes with multiple lines
logic [2:0] lg1_nseq ; // Sequence counter for geometric shapes with multiple lines
logic [2:0] lg2_nseq ; // Sequence counter for geometric shapes with multiple lines
C) When a geometric shape is called, these lines initialize the linegen params: 538-551
// Depending on the selected draw command+fill bit, this sets the number of sequences to count down from for each linegen once each linegen finishes.
lg1_seq_end <= LUT_LG_CMD_SEQ_SIZE[{command_in[3:0],1'b0}];
lg2_seq_end <= LUT_LG_CMD_SEQ_SIZE[{command_in[3:0],1'b1}];
lg1_seq <= 0;
lg2_seq <= 0;
lgen_1ax <= LUT_LG1_SEL_XY[{command_in[3:0],5'b00000}] ;
lgen_1ay <= LUT_LG1_SEL_XY[{command_in[3:0],5'b00001}] ;
lgen_1bx <= LUT_LG1_SEL_XY[{command_in[3:0],5'b00010}] ;
lgen_1by <= LUT_LG1_SEL_XY[{command_in[3:0],5'b00011}] ;
lgen_2ax <= LUT_LG2_SEL_XY[{command_in[3:0],5'b00000}] ;
lgen_2ay <= LUT_LG2_SEL_XY[{command_in[3:0],5'b00001}] ;
lgen_2bx <= LUT_LG2_SEL_XY[{command_in[3:0],5'b00010}] ;
lgen_2by <= LUT_LG2_SEL_XY[{command_in[3:0],5'b00011}] ;
D) When the new one-shot 'line_complete' fires, it increments updates the following linegen settings here: 375-390
if ( geo_run ) begin // Decrement each line sequence counter once their line has completed.
if (line_1_done && (lg1_seq!=lg1_seq_end)) begin
lg1_seq <= lg1_nseq;
lgen_1ax <= LUT_LG1_SEL_XY[{geo_shape[3:0],lg1_nseq,2'b00}] ;
lgen_1ay <= LUT_LG1_SEL_XY[{geo_shape[3:0],lg1_nseq,2'b01}] ;
lgen_1bx <= LUT_LG1_SEL_XY[{geo_shape[3:0],lg1_nseq,2'b10}] ;
lgen_1by <= LUT_LG1_SEL_XY[{geo_shape[3:0],lg1_nseq,2'b11}] ;
end
if (line_2_done && (lg2_seq!=lg2_seq_end)) begin
lg2_seq <= lg2_nseq;
lgen_2ax <= LUT_LG2_SEL_XY[{geo_shape[3:0],lg2_nseq,2'b00}] ;
lgen_2ay <= LUT_LG2_SEL_XY[{geo_shape[3:0],lg2_nseq,2'b01}] ;
lgen_2bx <= LUT_LG2_SEL_XY[{geo_shape[3:0],lg2_nseq,2'b10}] ;
lgen_2by <= LUT_LG2_SEL_XY[{geo_shape[3:0],lg2_nseq,2'b11}] ;
end
end
E) This is the current sequence combinational logic for the linegens: 306-323
// If any of the linegens or blitter are working, geo_run needs to go immediately HIGH to stop loading new commands
geo_run = (lg1_seq!=lg1_seq_end) || (lg2_seq!=lg2_seq_end) || line_gen_3_running ;
// Line generator running logic
line_gen_starter = !reset && ( !fifo_cmd_rdy_n && !geo_run ) && ( command_in[7:5] == 3'd0 && command_in[2:0] != 3'd0 ) ; // for now, only the draw line command
linegen_1_run = line_gen_1_running || (lg1_seq!=lg1_seq_end && !line_1_done) ; // initiate linegen1 when linegen2 is not running
linegen_2_run = (line_gen_2_running || ( y_stopped_1 )) && !(line_2_done && (lg2_seq!=lg2_seq_end)) ; // initiate linegen2 after linegen1 has its first stop
linegen_3_run = 1'b0 ; // not used at the moment
// Starting and ending coordinate selection
// Only release a stop once the opposite linegen goes from a non-y-stopped state to a y-stopped-state, or that linegen has completed a line
y_stop_en_1 = ( !(y_stopped_2 && !last_y_stopped_2) ) && (lg2_seq!=lg2_seq_end) ;
y_stop_en_2 = ( !(y_stopped_1 && !last_y_stopped_1) ) && (lg1_seq!=lg1_seq_end) ;
lg1_nseq = lg1_seq + 1; // prepare an array with the next sequence number
lg2_nseq = lg2_seq + 1; // prepare an array with the next sequence number
You now need to test the first 1..5 functioning commands. Make sure they work on the Z80. Make sure the simulation look good. Update your comments. Check that the Y position from linegen 1&2 stay synchronized with odd angle lines. Make sure multiple lines works right.
Next you need to activate the 'Fill' commands.