Arlet wrote:
...or (depending on your preferred style)...
Only someone who has mastered something can have a style. Mastery is knowing not only what to do, but more importantly what not to do. Right now I only know what looks right in ISim, and I look at the console. Also I check the design summary. Regular runs of smartexplorer are common at this stage, I have it set to 24 runs max. To Xilinx' credit, it always seems to find a way to keep that speed consistent but has gotten to 18 runs a couple times. Very smart program, I think it learns...
But sometimes after long runs of smartexplorer, my computer crashes and erroneously saves data after a blue screen of death. Last time it cut off all the vectors at the end of my 65O16.b software program. I was modifying all sorts of code only to finally recognize the cpu was in a loop because as65 was not seeing the NMI/IRQ/RES vectors. They were gone! Lines of code and my hours of wasted testing things that had worked!
Anyway, I'll post the most up to date LineGen code in the hopes that maybe someone can find a way to speed it up, although it is plenty fast. A cycle here or there can have great effects in the end though:
Code:
module LineGen ( input clk,
input lineCS,
input [15:0] cpuDO,
input [1:0] cpuAB,
output reg RAMWE,
output reg [9:0] X,
output reg [8:0] Y
);
reg [9:0] x0, x1, dx, x0t, x1t; //internal module registers
reg [8:0] y0, y1, dy, y0t, y1t;
reg [16:0] D; //error accumulator + carry bit. if D[16] = 1, it is negative
reg steep; //1 when dy>dx
reg dyneg; //1 when dy is negative
reg dxneg; //1 when dx is negative
reg [2:0] state;
parameter WAIT = 0, LOAD = 1, SLOPE = 2, DXDY = 3, CALC1 = 4, CALC2 = 5, PLOT = 6, DELAY = 7;
always @(posedge clk) begin
if (lineCS && cpuAB == 2'b00)
x0t <= cpuDO;
if (lineCS && cpuAB == 2'b01)
y0t <= cpuDO;
if (lineCS && cpuAB == 2'b10)
x1t <= cpuDO;
if (lineCS && cpuAB == 2'b11)
y1t <= cpuDO;
end
always @(posedge clk) begin
state <= WAIT;
case (state)
WAIT:
if (lineCS && cpuAB == 2'b11)
state <= LOAD;
else state <= WAIT;
LOAD:
state <= SLOPE;
SLOPE:
state <= DXDY;
DXDY:
state <= CALC1;
CALC1:
state <= CALC2;
CALC2:
state <= PLOT;
PLOT:
begin
if (!dyneg && steep) //e.g. (0,0) to (2,10)
if (y0 != y1)
state <= DELAY;
else state <= WAIT;
if (!dyneg && !steep) //e.g. (0,0) to (10,10)
if (x0 != x1)
state <= DELAY;
else state <= WAIT;
if (dyneg && !steep) //e.g. (0,10) to (10,0)
if (x0 != x1)
state <= DELAY;
else state <= WAIT;
if (dyneg && steep) //e.g. (0,20) to (2,0)
if (y0 != y1)
state <= DELAY;
else state <= WAIT;
end
DELAY:
state <= CALC2;
endcase
end
always @(posedge clk) begin
case (state)
WAIT:
begin
RAMWE <= 0;
if (x0t > x1t)
dxneg <= 1;
else dxneg <= 0;
end
LOAD:
if (dxneg)
begin
x0 <= x1t;
y0 <= y1t;
x1 <= x0t;
y1 <= y0t;
end
else begin
x0 <= x0t;
y0 <= y0t;
x1 <= x1t;
y1 <= y1t;
end
SLOPE:
if (y0 > y1)
dyneg <= 1;
else dyneg <= 0;
DXDY:
begin
dx <= x1 - x0;
RAMWE <= 1;
X <= x0;
Y <= y0;
if (dyneg)
dy <= y0 - y1;
else dy <= y1 - y0;
end
CALC1:
if (dx >= dy) begin
steep <= 0;
D <= (dy*2 - dx);
end
else begin
steep <= 1;
D <= (dx*2 - dy);
end
CALC2:
begin
RAMWE <= 0;
if (steep) begin
if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dx*2 - dy*2);
end
else begin
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + dx*2;
end
end
else if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dy*2 - dx*2);
end
else begin
x0 <= x0 + 1;
D <= D + dy*2;
end
end
PLOT:
begin
RAMWE <= 1;
X <= x0;
Y <= y0;
end
DELAY:
RAMWE <= 1;
endcase
end
endmodule
I actually did have to delay the write to the RAM 1 cycle from LineGen (as you can see). I have problems now with data outputted from the cpu.
My SRAMif module has changed for the better, but as I said there are problems, and now it looks nasty to me to use 'if' statements when using a module for a RAM interface:
Code:
module SRAMif( input clk,
input vramCS,
input cpuWE,
input RAMWE,
inout [15:0] SRD,
input [15:0] cpuDO,
input [15:0] BACCout,
input [20:0] Vaddr,
input [31:0] cpuAB,
input [9:0] X,
input [8:0] Y,
output [20:0] SRaddr,
output reg [15:0] SRDO,
output SRWEn
);
always @(posedge clk)
if (vramCS && !cpuWE && !RAMWE)
SRDO <= SRD; //when reading from SyncRAM, put data into reg
else if (!vramCS)
SRDO <= 16'h0000; //else reg will output zeroes when vram is not selected
reg [20:0] cpuABopt;
always @* begin //optimize the videoRAM address for plotting (X,Y) in the (LSB,MSB) for indirect indexed
cpuABopt [20:19] <= 2'b00; //bank bits
cpuABopt [18:10] <= cpuAB [24:16]; //Y[8:0]
cpuABopt [9:0] <= cpuAB [9:0]; //X[9:0]
end
assign SRaddr = RAMWE ? {2'b00, Y, X} : vramCS ? cpuABopt : Vaddr; //MUX the SyncRAM address for video timing & cpu access
assign SRWEn = ~((vramCS && cpuWE) || RAMWE); //SyncRAM write enable, active low during a write to video memory by cpu
assign SRD = SRWEn ? 16'hZZZZ : BACCout; //I/O MUX'd latch to SyncRAM databus. High 'Z' during a read
endmodule