mirror of
https://github.com/MiSTer-devel/CDi_MiSTer.git
synced 2026-06-14 03:04:32 +00:00
Partial revert of 1c41f27f
During combined ICA0 and ICA1 activity, memory access by CPU
was not possible for multiple lines.
309 lines
11 KiB
Systemverilog
309 lines
11 KiB
Systemverilog
`include "bus.svh"
|
|
|
|
// ICA Image Control Area
|
|
// Configures during VBLANK
|
|
|
|
// DCA Dynamic Control Area
|
|
// Configures during HBLANK
|
|
// Limited to a maximum of 8 writes per line
|
|
|
|
//`define DEBUG
|
|
`define dp(statement) `ifdef DEBUG $display``statement `endif
|
|
|
|
module ica_dca_ctrl (
|
|
input clk,
|
|
input reset,
|
|
output bit [21:0] address,
|
|
output bit as,
|
|
input [15:0] din,
|
|
input bus_ack,
|
|
|
|
//output burst,
|
|
input burstdata_valid,
|
|
|
|
input dca_read,
|
|
input hblank,
|
|
input parity, // 1 for odd frame, 0 for even frame
|
|
|
|
output [6:0] register_adr,
|
|
output [23:0] register_data,
|
|
output register_write,
|
|
|
|
output reload_vsr,
|
|
output [21:0] vsr,
|
|
|
|
output bit irq,
|
|
output display_parameters_s disp_params
|
|
);
|
|
|
|
parameter bit unit_index = 0;
|
|
localparam bit [21:0] odd_ica_start = 22'h400;
|
|
localparam bit [21:0] even_ica_start = 22'h404;
|
|
|
|
bit [21:0] ica_pointer;
|
|
bit [21:0] dca_pointer;
|
|
bit [21:0] next_line_dca_pointer;
|
|
bit [3:0] dca_burst_cnt;
|
|
bit [31:0] instruction;
|
|
|
|
bit [4:0] stall_cnt;
|
|
|
|
enum bit [3:0] {
|
|
IDLE,
|
|
ICA_READ0,
|
|
ICA_READ1,
|
|
ICA_WAIT_FOR_ACK,
|
|
ICA_EXECUTE,
|
|
ICA_STALL,
|
|
DCA_READ0,
|
|
DCA_READ1,
|
|
DCA_READ2,
|
|
DCA_READ3
|
|
} state;
|
|
|
|
`ifdef VERILATOR
|
|
string unit_name;
|
|
initial begin
|
|
$sformat(unit_name, "ICA%d", unit_index);
|
|
end
|
|
`endif
|
|
|
|
assign register_adr = instruction[30:24];
|
|
assign register_data = instruction[23:0];
|
|
assign register_write = execute_instruction && instruction[31];
|
|
|
|
assign vsr = instruction[21:0];
|
|
assign reload_vsr = (execute_instruction && instruction[31:28] == 5) || (execute_instruction && ica_ended && instruction[31:28] == 4);
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (register_write)
|
|
`dp(("%s Write %x %x %b", unit_name, {1'b1, register_adr
|
|
}, register_data, register_data));
|
|
end
|
|
|
|
bit ica_ended;
|
|
bit dca_active;
|
|
|
|
bit execute_instruction;
|
|
// A high level indicates a DCA access was not aligned on a 64 bit boundary
|
|
// We need to ignore the second instruction of the first and last burst to
|
|
// fix this. Also we need one additional burst
|
|
bit dca_misaligned;
|
|
|
|
always_ff @(posedge clk) begin
|
|
irq <= 0;
|
|
disp_params.strobe <= 0;
|
|
execute_instruction <= 0;
|
|
|
|
if (reset) begin
|
|
ica_pointer <= parity ? odd_ica_start : even_ica_start;
|
|
as <= 0;
|
|
state <= IDLE;
|
|
ica_ended <= 0;
|
|
dca_burst_cnt <= 0;
|
|
dca_active <= 0;
|
|
dca_misaligned <= 0;
|
|
|
|
disp_params.cm <= 0;
|
|
disp_params.mf <= kMosaicFactor2;
|
|
disp_params.ft <= kBitmap;
|
|
instruction <= 0;
|
|
end else begin
|
|
|
|
case (state)
|
|
IDLE: begin
|
|
if (!ica_ended) begin
|
|
state <= ICA_READ0;
|
|
address <= ica_pointer;
|
|
// Read one instruction of 4 byte
|
|
ica_pointer <= ica_pointer + 4;
|
|
`dp(("ICA%d Start reading at %x", unit_index, ica_pointer));
|
|
// check for alignment on 32 bit boundary
|
|
assert (ica_pointer[1:0] == 0);
|
|
as <= 1;
|
|
end else if (dca_read) begin
|
|
dca_active <= 1;
|
|
// ICA has ended. Wait for hblanks to
|
|
state <= DCA_READ0;
|
|
as <= 1;
|
|
address <= dca_pointer;
|
|
// check at least for alignment on 32 bit boundary
|
|
assert (dca_pointer[1:0] == 0);
|
|
|
|
if (dca_pointer[2]) begin
|
|
// This is bad. The access is not on a 64 bit boundary
|
|
// Only use the first 2 words on the first and last burst
|
|
// Also we need one more additional burst
|
|
dca_pointer <= dca_pointer + 4;
|
|
dca_burst_cnt <= 8;
|
|
dca_misaligned <= 1;
|
|
end else begin
|
|
// We need to read 16 instructions from DCA
|
|
// Always read in bursts of 4. This causes 2 instructions
|
|
// per burst.
|
|
// We need 8 bursts to complete the line
|
|
dca_pointer <= dca_pointer + 8;
|
|
dca_burst_cnt <= 7;
|
|
dca_misaligned <= 0;
|
|
end
|
|
$sformat(unit_name, "DCA%d", unit_index);
|
|
`dp(("DCA%d Start reading at %x", unit_index, dca_pointer));
|
|
next_line_dca_pointer <= dca_pointer + 8 * 8;
|
|
end
|
|
end
|
|
ICA_READ0: begin
|
|
if (burstdata_valid) begin
|
|
instruction[31:16] <= din;
|
|
state <= ICA_READ1;
|
|
end
|
|
end
|
|
ICA_READ1: begin
|
|
if (burstdata_valid) begin
|
|
instruction[15:0] <= din;
|
|
state <= ICA_WAIT_FOR_ACK;
|
|
execute_instruction <= 1;
|
|
end
|
|
end
|
|
ICA_WAIT_FOR_ACK: begin
|
|
if (bus_ack) begin
|
|
as <= 0;
|
|
state <= ICA_EXECUTE;
|
|
end
|
|
end
|
|
ICA_EXECUTE: begin
|
|
state <= ICA_STALL;
|
|
end
|
|
ICA_STALL: begin
|
|
stall_cnt <= stall_cnt + 1;
|
|
if (stall_cnt == 0) state <= IDLE;
|
|
end
|
|
|
|
DCA_READ0: begin
|
|
if (burstdata_valid) begin
|
|
instruction[31:16] <= din;
|
|
state <= DCA_READ1;
|
|
end
|
|
end
|
|
DCA_READ1: begin
|
|
if (burstdata_valid) begin
|
|
instruction[15:0] <= din;
|
|
state <= DCA_READ2;
|
|
execute_instruction <= dca_active;
|
|
end
|
|
end
|
|
DCA_READ2: begin
|
|
if (burstdata_valid) begin
|
|
instruction[31:16] <= din;
|
|
state <= DCA_READ3;
|
|
end
|
|
end
|
|
DCA_READ3: begin
|
|
if (burstdata_valid) begin
|
|
instruction[15:0] <= din;
|
|
if (dca_misaligned) begin
|
|
// With DCA not aligned on 64 bit boundary, we must throw away the second word of the first and
|
|
// the last burst
|
|
execute_instruction <= dca_active && dca_burst_cnt != 8 && dca_burst_cnt != 0;
|
|
end else begin
|
|
execute_instruction <= dca_active;
|
|
end
|
|
|
|
if (dca_burst_cnt == 8)
|
|
assert (dca_misaligned); // check for the simulation
|
|
end
|
|
|
|
if (bus_ack) begin
|
|
if (dca_burst_cnt == 0 || !dca_active) begin
|
|
state <= IDLE;
|
|
|
|
dca_pointer <= next_line_dca_pointer;
|
|
dca_active <= 0;
|
|
as <= 0;
|
|
end else begin
|
|
state <= DCA_READ0;
|
|
as <= 1;
|
|
address <= dca_pointer;
|
|
// `dp(("DCA%d Continue reading at %x", unit_index, dca_pointer);
|
|
|
|
dca_pointer <= dca_pointer + 8;
|
|
dca_burst_cnt <= dca_burst_cnt - 1;
|
|
end
|
|
end
|
|
end
|
|
default: begin
|
|
end
|
|
endcase
|
|
|
|
if (execute_instruction) begin
|
|
// `dp(("%s instruction %x", unit_name, instruction);
|
|
case (instruction[31:28])
|
|
0: begin
|
|
// stop until next field
|
|
ica_ended <= 1;
|
|
`dp(("%s STOP", unit_name));
|
|
|
|
dca_active <= 0;
|
|
end
|
|
1: begin
|
|
// no operation
|
|
// `dp(("%s NOP", unit_name));
|
|
end
|
|
2: begin
|
|
// reload dcp
|
|
if (ica_ended) begin
|
|
`dp(("%s NOP (Reload DCP)", unit_name));
|
|
end else begin
|
|
dca_pointer <= instruction[21:0];
|
|
`dp(("%s Reload DCP %x", unit_name, instruction[21:0]));
|
|
end
|
|
end
|
|
3: begin
|
|
// reload dcp and stop
|
|
dca_pointer <= instruction[21:0];
|
|
next_line_dca_pointer <= instruction[21:0];
|
|
dca_active <= 0;
|
|
ica_ended <= 1;
|
|
`dp(("%s Reload DCP and STOP %x", unit_name, instruction[21:0]));
|
|
end
|
|
4: begin
|
|
// reload ica pointer
|
|
ica_pointer <= instruction[21:0];
|
|
|
|
if (ica_ended) `dp(("%s Reload VSR %x", unit_name, instruction[21:0]));
|
|
else `dp(("%s Reload ICA %x", unit_name, instruction[21:0]));
|
|
end
|
|
5: begin
|
|
// reload vsr pointer and stop
|
|
`dp(("%s Reload VSR and STOP %x", unit_name, instruction[21:0]));
|
|
ica_ended <= 1;
|
|
dca_active <= 0;
|
|
|
|
end
|
|
6: begin
|
|
// interrupt
|
|
`dp(("%s INTERRUPT", unit_name));
|
|
irq <= 1;
|
|
end
|
|
7: begin
|
|
// reload display parameters
|
|
//assert(instruction[27]);
|
|
//assert(!instruction[5]);
|
|
|
|
if (instruction[27]) begin
|
|
disp_params.cm <= instruction[4];
|
|
disp_params.mf <= mosaic_factor_e'(instruction[3:2]);
|
|
disp_params.ft <= file_type_e'(instruction[1:0]);
|
|
disp_params.strobe <= 1;
|
|
|
|
`dp(("%s RELOAD DISPLAY PARAMETERS %b", unit_name, instruction[4:0]));
|
|
end
|
|
end
|
|
default: begin
|
|
// no command but probably a register write
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
end
|
|
endmodule
|