-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmcu_interface.sv
137 lines (112 loc) · 4.1 KB
/
mcu_interface.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
module MCUInterface(
input clock,
output logic [16:0] videoAddressOffset,
output videoHighResMode,
input videoVBlank,
output logic [16:0] memoryWriteAddress,
output logic memoryWriteRequest,
output logic [7:0] memoryWriteData,
input memoryWriteComplete,
output logic [16:0] memoryReadAddress,
input [7:0] memoryReadData,
input mpuChipSelect,
input mpuWriteEnable,
input [2:0] mpuRegisterSelect,
inout [7:0] mpuDataBus,
output mpuVideoInterrupt
);
parameter
REGISTER_X_LOW = 0,
REGISTER_X_HIGH = 1,
REGISTER_Y = 2,
REGISTER_DATA = 3,
REGISTER_CONTROL = 4,
REGISTER_Y_OFFSET = 5;
parameter
CONTROL_X_AUTOINCREMENT = 0,
CONTROL_HIGH_RES_MODE = 1,
CONTROL_VBLANK_INTERRUPT = 2,
CONTROL_VBLANK_ACTIVE = 3;
logic registerWriteRequest;
logic registerReadRequest;
logic [7:0] dataRegister;
logic [2:0] controlRegister;
logic controlVBlank;
logic pixelWriteRequest;
logic [16:0] pixelWriteAddress;
logic [16:0] pixelWriteAddressNext;
logic xIncrement;
always_comb begin
xIncrement = controlRegister[CONTROL_X_AUTOINCREMENT];
videoHighResMode = controlRegister[CONTROL_HIGH_RES_MODE];
end
always_comb begin
registerWriteRequest = mpuChipSelect && !mpuWriteEnable;
registerReadRequest = mpuChipSelect && mpuWriteEnable;
if (registerReadRequest) begin
case (mpuRegisterSelect)
REGISTER_X_LOW : mpuDataBus = pixelWriteAddress[7:0];
REGISTER_X_HIGH : mpuDataBus = pixelWriteAddress[8];
REGISTER_Y : mpuDataBus = pixelWriteAddress[16:9];
REGISTER_DATA : mpuDataBus = memoryReadData;
REGISTER_CONTROL : mpuDataBus = { 4'b0000 , videoVBlank , controlRegister };
REGISTER_Y_OFFSET : mpuDataBus = videoAddressOffset[16:9];
default : mpuDataBus = 8'hff;
endcase
end else begin
mpuDataBus = 8'bz;
end
end
logic videoInterruptClearRequest;
logic videoInterruptClearStatus;
always_ff @(posedge clock) begin
if (!controlRegister[CONTROL_VBLANK_INTERRUPT] || videoInterruptClearRequest != videoInterruptClearStatus) begin
mpuVideoInterrupt <= 1;
videoInterruptClearStatus <= videoInterruptClearRequest;
end
if (videoVBlank) begin
if (!controlVBlank && controlRegister[CONTROL_VBLANK_INTERRUPT]) begin
mpuVideoInterrupt <= 0;
controlVBlank <= 1;
end
end else begin
controlVBlank <= 0;
end
end
always_comb begin
memoryReadAddress = pixelWriteAddressNext;
end
always_ff @(posedge mpuChipSelect) begin
if (registerWriteRequest) begin
case (mpuRegisterSelect)
REGISTER_X_LOW : pixelWriteAddressNext[7:0] <= mpuDataBus;
REGISTER_X_HIGH : pixelWriteAddressNext[8] <= mpuDataBus[0];
REGISTER_Y : pixelWriteAddressNext[16:9] <= mpuDataBus;
REGISTER_DATA : begin
dataRegister <= mpuDataBus;
pixelWriteAddress <= pixelWriteAddressNext;
pixelWriteRequest <= ~pixelWriteRequest;
end
REGISTER_CONTROL : begin
controlRegister <= mpuDataBus[2:0];
videoInterruptClearRequest <= ~videoInterruptClearRequest;
end
REGISTER_Y_OFFSET : videoAddressOffset <= { mpuDataBus , 9'b0 };
endcase
end
if (mpuRegisterSelect == REGISTER_DATA && xIncrement) begin
pixelWriteAddressNext <= pixelWriteAddressNext + 1'b1;
end
end
logic [2:0] pixelWriteRequestDelay;
always_ff @(posedge clock) begin
pixelWriteRequestDelay <= { pixelWriteRequestDelay[1:0] , pixelWriteRequest };
if (memoryWriteRequest) begin
memoryWriteRequest <= ~memoryWriteComplete;
end else if (pixelWriteRequestDelay[2] != pixelWriteRequestDelay[1]) begin
memoryWriteAddress <= pixelWriteAddress;
memoryWriteData <= dataRegister;
memoryWriteRequest <= 1;
end
end
endmodule