mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-07 00:17:07 +00:00
[NES] Fixes audio in SM3 + cleanup
This commit is contained in:
@@ -281,6 +281,7 @@ set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_n
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCS
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CKE
|
||||
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CLK
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE src/apu.sv
|
||||
set_global_assignment -name VHDL_FILE t65/T65_Pack.vhd
|
||||
set_global_assignment -name VHDL_FILE t65/T65_MCode.vhd
|
||||
set_global_assignment -name VHDL_FILE t65/T65_ALU.vhd
|
||||
@@ -304,6 +305,5 @@ set_global_assignment -name VERILOG_FILE src/nes.v
|
||||
set_global_assignment -name VERILOG_FILE src/MicroCode.v
|
||||
set_global_assignment -name VERILOG_FILE src/hq2x.v
|
||||
set_global_assignment -name VERILOG_FILE src/dsp.v
|
||||
set_global_assignment -name VERILOG_FILE src/apu.v
|
||||
set_global_assignment -name VERILOG_FILE mist/NES_mist.v
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
@@ -71,7 +71,7 @@ reg [2:0] SeqPos;
|
||||
wire [10:0] ShiftedPeriod = (Period >> SweepShift);
|
||||
wire [10:0] PeriodRhs = (SweepNegate ? (~ShiftedPeriod + {10'b0, sq2}) : ShiftedPeriod);
|
||||
wire [11:0] NewSweepPeriod = Period + PeriodRhs;
|
||||
wire ValidFreq = Period[10:3] >= 8 && (SweepNegate || !NewSweepPeriod[11]);
|
||||
wire ValidFreq = (|Period[10:3]) && (SweepNegate || !NewSweepPeriod[11]);
|
||||
|
||||
always @(posedge clk) if (reset) begin
|
||||
LenCtr <= 0;
|
||||
@@ -131,14 +131,14 @@ always @(posedge clk) if (reset) begin
|
||||
if (TimerCtr == 0) begin
|
||||
// Timer was clocked
|
||||
TimerCtr <= {Period, 1'b0};
|
||||
SeqPos <= SeqPos - 1;
|
||||
SeqPos <= SeqPos - 1'd1;
|
||||
end else begin
|
||||
TimerCtr <= TimerCtr - 1;
|
||||
TimerCtr <= TimerCtr - 1'd1;
|
||||
end
|
||||
|
||||
// Clock the length counter?
|
||||
if (LenCtr_Clock && LenCtr != 0 && !LenCtrHalt) begin
|
||||
LenCtr <= LenCtr - 1;
|
||||
LenCtr <= LenCtr - 1'd1;
|
||||
end
|
||||
|
||||
// Clock the sweep unit?
|
||||
@@ -148,7 +148,7 @@ always @(posedge clk) if (reset) begin
|
||||
if (SweepEnable && SweepShift != 0 && ValidFreq)
|
||||
Period <= NewSweepPeriod[10:0];
|
||||
end else begin
|
||||
SweepDivider <= SweepDivider - 1;
|
||||
SweepDivider <= SweepDivider - 1'd1;
|
||||
end
|
||||
if (SweepReset)
|
||||
SweepDivider <= SweepPeriod;
|
||||
@@ -164,9 +164,9 @@ always @(posedge clk) if (reset) begin
|
||||
end else if (EnvDivider == 0) begin
|
||||
EnvDivider <= Volume;
|
||||
if (Envelope != 0 || EnvLoop)
|
||||
Envelope <= Envelope - 1;
|
||||
Envelope <= Envelope - 1'd1;
|
||||
end else begin
|
||||
EnvDivider <= EnvDivider - 1;
|
||||
EnvDivider <= EnvDivider - 1'd1;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -252,12 +252,12 @@ module TriangleChan(input clk, input ce, input reset,
|
||||
if (TimerCtr == 0) begin
|
||||
TimerCtr <= Period;
|
||||
end else begin
|
||||
TimerCtr <= TimerCtr - 1;
|
||||
TimerCtr <= TimerCtr - 1'd1;
|
||||
end
|
||||
//
|
||||
// Clock the length counter?
|
||||
if (LenCtr_Clock && !LenCtrZero && !LenCtrHalt) begin
|
||||
LenCtr <= LenCtr - 1;
|
||||
LenCtr <= LenCtr - 1'd1;
|
||||
end
|
||||
//
|
||||
// Clock the linear counter?
|
||||
@@ -265,7 +265,7 @@ module TriangleChan(input clk, input ce, input reset,
|
||||
if (LinHalt)
|
||||
LinCtr <= LinCtrPeriod;
|
||||
else if (!LinCtrZero)
|
||||
LinCtr <= LinCtr - 1;
|
||||
LinCtr <= LinCtr - 1'd1;
|
||||
if (!LinCtrl)
|
||||
LinHalt <= 0;
|
||||
end
|
||||
@@ -276,7 +276,7 @@ module TriangleChan(input clk, input ce, input reset,
|
||||
//
|
||||
// Clock the sequencer position
|
||||
if (TimerCtr == 0 && !LenCtrZero && !LinCtrZero)
|
||||
SeqPos <= SeqPos + 1;
|
||||
SeqPos <= SeqPos + 1'd1;
|
||||
end
|
||||
// Generate the output
|
||||
assign Sample = SeqPos[3:0] ^ {4{~SeqPos[4]}};
|
||||
@@ -371,11 +371,11 @@ module NoiseChan(input clk, input ce, input reset,
|
||||
Shift[0] ^ (ShortMode ? Shift[6] : Shift[1]),
|
||||
Shift[14:1]};
|
||||
end else begin
|
||||
TimerCtr <= TimerCtr - 1;
|
||||
TimerCtr <= TimerCtr - 1'd1;
|
||||
end
|
||||
// Clock the length counter?
|
||||
if (LenCtr_Clock && LenCtr != 0 && !LenCtrHalt) begin
|
||||
LenCtr <= LenCtr - 1;
|
||||
LenCtr <= LenCtr - 1'd1;
|
||||
end
|
||||
// Clock the envelope generator?
|
||||
if (Env_Clock) begin
|
||||
@@ -386,11 +386,11 @@ module NoiseChan(input clk, input ce, input reset,
|
||||
end else if (EnvDivider == 0) begin
|
||||
EnvDivider <= Volume;
|
||||
if (Envelope != 0)
|
||||
Envelope <= Envelope - 1;
|
||||
Envelope <= Envelope - 1'd1;
|
||||
else if (EnvLoop)
|
||||
Envelope <= 15;
|
||||
end else
|
||||
EnvDivider <= EnvDivider - 1;
|
||||
EnvDivider <= EnvDivider - 1'd1;
|
||||
end
|
||||
if (!Enabled)
|
||||
LenCtr <= 0;
|
||||
@@ -398,7 +398,7 @@ module NoiseChan(input clk, input ce, input reset,
|
||||
// Produce the output signal
|
||||
assign Sample =
|
||||
(LenCtr == 0 || Shift[0]) ?
|
||||
0 :
|
||||
4'd0 :
|
||||
(EnvDisable ? Volume : Envelope);
|
||||
endmodule
|
||||
|
||||
@@ -429,7 +429,6 @@ module DmcChan(input clk, input ce, input reset,
|
||||
reg [7:0] SampleBuffer; // Next value to be loaded into shift reg
|
||||
reg HasSampleBuffer; // Sample buffer is nonempty
|
||||
reg HasShiftReg; // Shift reg is non empty
|
||||
reg [8:0] NewPeriod[0:15];
|
||||
reg DmcEnabled;
|
||||
reg [1:0] ActivationDelay;
|
||||
assign DmaAddr = {1'b1, Address};
|
||||
@@ -439,24 +438,13 @@ module DmcChan(input clk, input ce, input reset,
|
||||
|
||||
assign DmaReq = !HasSampleBuffer && DmcEnabled && !ActivationDelay[0];
|
||||
|
||||
initial begin
|
||||
NewPeriod[0] = 428;
|
||||
NewPeriod[1] = 380;
|
||||
NewPeriod[2] = 340;
|
||||
NewPeriod[3] = 320;
|
||||
NewPeriod[4] = 286;
|
||||
NewPeriod[5] = 254;
|
||||
NewPeriod[6] = 226;
|
||||
NewPeriod[7] = 214;
|
||||
NewPeriod[8] = 190;
|
||||
NewPeriod[9] = 160;
|
||||
NewPeriod[10] = 142;
|
||||
NewPeriod[11] = 128;
|
||||
NewPeriod[12] = 106;
|
||||
NewPeriod[13] = 84;
|
||||
NewPeriod[14] = 72;
|
||||
NewPeriod[15] = 54;
|
||||
end
|
||||
wire [8:0] NewPeriod[16] = '{
|
||||
428, 380, 340, 320,
|
||||
286, 254, 226, 214,
|
||||
190, 160, 142, 128,
|
||||
106, 84, 72, 54
|
||||
};
|
||||
|
||||
// Shift register initially loaded with 07
|
||||
always @(posedge clk) begin
|
||||
if (reset) begin
|
||||
@@ -512,7 +500,7 @@ module DmcChan(input clk, input ce, input reset,
|
||||
endcase
|
||||
end
|
||||
|
||||
Cycles <= Cycles - 1;
|
||||
Cycles <= Cycles - 1'd1;
|
||||
if (Cycles == 1) begin
|
||||
Cycles <= NewPeriod[Freq];
|
||||
if (HasShiftReg) begin
|
||||
@@ -523,7 +511,7 @@ module DmcChan(input clk, input ce, input reset,
|
||||
end
|
||||
end
|
||||
ShiftReg <= {1'b0, ShiftReg[7:1]};
|
||||
BitsUsed <= BitsUsed + 1;
|
||||
BitsUsed <= BitsUsed + 1'd1;
|
||||
if (BitsUsed == 7) begin
|
||||
HasShiftReg <= HasSampleBuffer;
|
||||
ShiftReg <= SampleBuffer;
|
||||
@@ -533,8 +521,8 @@ module DmcChan(input clk, input ce, input reset,
|
||||
|
||||
// Acknowledge DMA?
|
||||
if (DmaAck) begin
|
||||
Address <= Address + 1;
|
||||
BytesLeft <= BytesLeft - 1;
|
||||
Address <= Address + 1'd1;
|
||||
BytesLeft <= BytesLeft - 1'd1;
|
||||
HasSampleBuffer <= 1;
|
||||
SampleBuffer <= DmaData;
|
||||
if (BytesLeft == 0) begin
|
||||
@@ -549,75 +537,56 @@ module DmcChan(input clk, input ce, input reset,
|
||||
end
|
||||
endmodule
|
||||
|
||||
module ApuLookupTable(input clk, input [7:0] in_a, input [7:0] in_b, output [15:0] out);
|
||||
reg [15:0] lookup[0:511];
|
||||
reg [15:0] tmp_a, tmp_b;
|
||||
initial begin
|
||||
lookup[ 0] = 0; lookup[ 1] = 760; lookup[ 2] = 1503; lookup[ 3] = 2228;
|
||||
lookup[ 4] = 2936; lookup[ 5] = 3627; lookup[ 6] = 4303; lookup[ 7] = 4963;
|
||||
lookup[ 8] = 5609; lookup[ 9] = 6240; lookup[ 10] = 6858; lookup[ 11] = 7462;
|
||||
lookup[ 12] = 8053; lookup[ 13] = 8631; lookup[ 14] = 9198; lookup[ 15] = 9752;
|
||||
lookup[ 16] = 10296; lookup[ 17] = 10828; lookup[ 18] = 11349; lookup[ 19] = 11860;
|
||||
lookup[ 20] = 12361; lookup[ 21] = 12852; lookup[ 22] = 13334; lookup[ 23] = 13807;
|
||||
lookup[ 24] = 14270; lookup[ 25] = 14725; lookup[ 26] = 15171; lookup[ 27] = 15609;
|
||||
lookup[ 28] = 16039; lookup[ 29] = 16461; lookup[ 30] = 16876; lookup[256] = 0;
|
||||
lookup[257] = 439; lookup[258] = 874; lookup[259] = 1306; lookup[260] = 1735;
|
||||
lookup[261] = 2160; lookup[262] = 2581; lookup[263] = 2999; lookup[264] = 3414;
|
||||
lookup[265] = 3826; lookup[266] = 4234; lookup[267] = 4639; lookup[268] = 5041;
|
||||
lookup[269] = 5440; lookup[270] = 5836; lookup[271] = 6229; lookup[272] = 6618;
|
||||
lookup[273] = 7005; lookup[274] = 7389; lookup[275] = 7769; lookup[276] = 8147;
|
||||
lookup[277] = 8522; lookup[278] = 8895; lookup[279] = 9264; lookup[280] = 9631;
|
||||
lookup[281] = 9995; lookup[282] = 10356; lookup[283] = 10714; lookup[284] = 11070;
|
||||
lookup[285] = 11423; lookup[286] = 11774; lookup[287] = 12122; lookup[288] = 12468;
|
||||
lookup[289] = 12811; lookup[290] = 13152; lookup[291] = 13490; lookup[292] = 13825;
|
||||
lookup[293] = 14159; lookup[294] = 14490; lookup[295] = 14818; lookup[296] = 15145;
|
||||
lookup[297] = 15469; lookup[298] = 15791; lookup[299] = 16110; lookup[300] = 16427;
|
||||
lookup[301] = 16742; lookup[302] = 17055; lookup[303] = 17366; lookup[304] = 17675;
|
||||
lookup[305] = 17981; lookup[306] = 18286; lookup[307] = 18588; lookup[308] = 18888;
|
||||
lookup[309] = 19187; lookup[310] = 19483; lookup[311] = 19777; lookup[312] = 20069;
|
||||
lookup[313] = 20360; lookup[314] = 20648; lookup[315] = 20935; lookup[316] = 21219;
|
||||
lookup[317] = 21502; lookup[318] = 21783; lookup[319] = 22062; lookup[320] = 22339;
|
||||
lookup[321] = 22615; lookup[322] = 22889; lookup[323] = 23160; lookup[324] = 23431;
|
||||
lookup[325] = 23699; lookup[326] = 23966; lookup[327] = 24231; lookup[328] = 24494;
|
||||
lookup[329] = 24756; lookup[330] = 25016; lookup[331] = 25274; lookup[332] = 25531;
|
||||
lookup[333] = 25786; lookup[334] = 26040; lookup[335] = 26292; lookup[336] = 26542;
|
||||
lookup[337] = 26791; lookup[338] = 27039; lookup[339] = 27284; lookup[340] = 27529;
|
||||
lookup[341] = 27772; lookup[342] = 28013; lookup[343] = 28253; lookup[344] = 28492;
|
||||
lookup[345] = 28729; lookup[346] = 28964; lookup[347] = 29198; lookup[348] = 29431;
|
||||
lookup[349] = 29663; lookup[350] = 29893; lookup[351] = 30121; lookup[352] = 30349;
|
||||
lookup[353] = 30575; lookup[354] = 30800; lookup[355] = 31023; lookup[356] = 31245;
|
||||
lookup[357] = 31466; lookup[358] = 31685; lookup[359] = 31904; lookup[360] = 32121;
|
||||
lookup[361] = 32336; lookup[362] = 32551; lookup[363] = 32764; lookup[364] = 32976;
|
||||
lookup[365] = 33187; lookup[366] = 33397; lookup[367] = 33605; lookup[368] = 33813;
|
||||
lookup[369] = 34019; lookup[370] = 34224; lookup[371] = 34428; lookup[372] = 34630;
|
||||
lookup[373] = 34832; lookup[374] = 35032; lookup[375] = 35232; lookup[376] = 35430;
|
||||
lookup[377] = 35627; lookup[378] = 35823; lookup[379] = 36018; lookup[380] = 36212;
|
||||
lookup[381] = 36405; lookup[382] = 36597; lookup[383] = 36788; lookup[384] = 36978;
|
||||
lookup[385] = 37166; lookup[386] = 37354; lookup[387] = 37541; lookup[388] = 37727;
|
||||
lookup[389] = 37912; lookup[390] = 38095; lookup[391] = 38278; lookup[392] = 38460;
|
||||
lookup[393] = 38641; lookup[394] = 38821; lookup[395] = 39000; lookup[396] = 39178;
|
||||
lookup[397] = 39355; lookup[398] = 39532; lookup[399] = 39707; lookup[400] = 39881;
|
||||
lookup[401] = 40055; lookup[402] = 40228; lookup[403] = 40399; lookup[404] = 40570;
|
||||
lookup[405] = 40740; lookup[406] = 40909; lookup[407] = 41078; lookup[408] = 41245;
|
||||
lookup[409] = 41412; lookup[410] = 41577; lookup[411] = 41742; lookup[412] = 41906;
|
||||
lookup[413] = 42070; lookup[414] = 42232; lookup[415] = 42394; lookup[416] = 42555;
|
||||
lookup[417] = 42715; lookup[418] = 42874; lookup[419] = 43032; lookup[420] = 43190;
|
||||
lookup[421] = 43347; lookup[422] = 43503; lookup[423] = 43659; lookup[424] = 43813;
|
||||
lookup[425] = 43967; lookup[426] = 44120; lookup[427] = 44273; lookup[428] = 44424;
|
||||
lookup[429] = 44575; lookup[430] = 44726; lookup[431] = 44875; lookup[432] = 45024;
|
||||
lookup[433] = 45172; lookup[434] = 45319; lookup[435] = 45466; lookup[436] = 45612;
|
||||
lookup[437] = 45757; lookup[438] = 45902; lookup[439] = 46046; lookup[440] = 46189;
|
||||
lookup[441] = 46332; lookup[442] = 46474; lookup[443] = 46615; lookup[444] = 46756;
|
||||
lookup[445] = 46895; lookup[446] = 47035; lookup[447] = 47173; lookup[448] = 47312;
|
||||
lookup[449] = 47449; lookup[450] = 47586; lookup[451] = 47722; lookup[452] = 47857;
|
||||
lookup[453] = 47992; lookup[454] = 48127; lookup[455] = 48260; lookup[456] = 48393;
|
||||
lookup[457] = 48526; lookup[458] = 48658;
|
||||
end
|
||||
always @(posedge clk) begin
|
||||
tmp_a <= lookup[{1'b0, in_a}];
|
||||
tmp_b <= lookup[{1'b1, in_b}];
|
||||
end
|
||||
assign out = tmp_a + tmp_b;
|
||||
module ApuLookupTable
|
||||
(
|
||||
input clk,
|
||||
input [7:0] in_a,
|
||||
input [7:0] in_b,
|
||||
output reg [15:0] out
|
||||
);
|
||||
|
||||
wire [15:0] lookup_a[256] = '{
|
||||
0, 760, 1503, 2228, 2936, 3627, 4303, 4963, 5609, 6240, 6858, 7462, 8053, 8631, 9198, 9752,
|
||||
10296, 10828, 11349, 11860, 12361, 12852, 13334, 13807, 14270, 14725, 15171, 15609, 16039, 16461, 16876, 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, 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, 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, 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, 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, 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, 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, 0
|
||||
};
|
||||
|
||||
wire [15:0] lookup_b[256] = '{
|
||||
0, 439, 874, 1306, 1735, 2160, 2581, 2999, 3414, 3826, 4234, 4639, 5041, 5440, 5836, 6229,
|
||||
6618, 7005, 7389, 7769, 8147, 8522, 8895, 9264, 9631, 9995, 10356, 10714, 11070, 11423, 11774, 12122,
|
||||
12468, 12811, 13152, 13490, 13825, 14159, 14490, 14818, 15145, 15469, 15791, 16110, 16427, 16742, 17055, 17366,
|
||||
17675, 17981, 18286, 18588, 18888, 19187, 19483, 19777, 20069, 20360, 20648, 20935, 21219, 21502, 21783, 22062,
|
||||
22339, 22615, 22889, 23160, 23431, 23699, 23966, 24231, 24494, 24756, 25016, 25274, 25531, 25786, 26040, 26292,
|
||||
26542, 26791, 27039, 27284, 27529, 27772, 28013, 28253, 28492, 28729, 28964, 29198, 29431, 29663, 29893, 30121,
|
||||
30349, 30575, 30800, 31023, 31245, 31466, 31685, 31904, 32121, 32336, 32551, 32764, 32976, 33187, 33397, 33605,
|
||||
33813, 34019, 34224, 34428, 34630, 34832, 35032, 35232, 35430, 35627, 35823, 36018, 36212, 36405, 36597, 36788,
|
||||
36978, 37166, 37354, 37541, 37727, 37912, 38095, 38278, 38460, 38641, 38821, 39000, 39178, 39355, 39532, 39707,
|
||||
39881, 40055, 40228, 40399, 40570, 40740, 40909, 41078, 41245, 41412, 41577, 41742, 41906, 42070, 42232, 42394,
|
||||
42555, 42715, 42874, 43032, 43190, 43347, 43503, 43659, 43813, 43967, 44120, 44273, 44424, 44575, 44726, 44875,
|
||||
45024, 45172, 45319, 45466, 45612, 45757, 45902, 46046, 46189, 46332, 46474, 46615, 46756, 46895, 47035, 47173,
|
||||
47312, 47449, 47586, 47722, 47857, 47992, 48127, 48260, 48393, 48526, 48658, 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, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
always @(posedge clk) begin
|
||||
out <= lookup_a[in_a] + lookup_b[in_b];
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
@@ -712,7 +681,7 @@ always @(posedge clk) if (reset) begin
|
||||
Cycles <= 4; // This needs to be 5 for proper power up behavior
|
||||
IrqCtr <= 0;
|
||||
end else if (ce) begin
|
||||
FrameInterrupt <= IrqCtr[1] ? 1 : (ADDR == 5'h15 && MR || ApuMW5 && ADDR[1:0] == 3 && DIN[6]) ? 0 : FrameInterrupt;
|
||||
FrameInterrupt <= IrqCtr[1] ? 1'd1 : (ADDR == 5'h15 && MR || ApuMW5 && ADDR[1:0] == 3 && DIN[6]) ? 1'd0 : FrameInterrupt;
|
||||
InternalClock <= !InternalClock;
|
||||
IrqCtr <= {IrqCtr[0], 1'b0};
|
||||
Cycles <= Cycles + 1;
|
||||
@@ -723,8 +692,6 @@ end else if (ce) begin
|
||||
end else if (Cycles == 14913) begin
|
||||
ClkE <= 1;
|
||||
ClkL <= 1;
|
||||
ClkE <= 1;
|
||||
ClkL <= 1;
|
||||
end else if (Cycles == 22371) begin
|
||||
ClkE <= 1;
|
||||
end else if (Cycles == 29829) begin
|
||||
@@ -1,357 +0,0 @@
|
||||
// Copyright (c) 2012-2013 Ludvig Strigeus
|
||||
// This program is GPL Licensed. See COPYING for the full license.
|
||||
|
||||
//`include "MicroCode.v"
|
||||
|
||||
module MyAddSub(input [7:0] A,B,
|
||||
input CI,ADD,
|
||||
output [7:0] S,
|
||||
output CO,OFL);
|
||||
wire C0,C1,C2,C3,C4,C5,C6;
|
||||
wire C6O;
|
||||
wire [7:0] I = A ^ B ^ {8{~ADD}};
|
||||
MUXCY_L MUXCY_L0 (.LO(C0),.CI(CI),.DI(A[0]),.S(I[0]) );
|
||||
MUXCY_L MUXCY_L1 (.LO(C1),.CI(C0),.DI(A[1]),.S(I[1]) );
|
||||
MUXCY_L MUXCY_L2 (.LO(C2),.CI(C1),.DI(A[2]),.S(I[2]) );
|
||||
MUXCY_L MUXCY_L3 (.LO(C3),.CI(C2),.DI(A[3]),.S(I[3]) );
|
||||
MUXCY_L MUXCY_L4 (.LO(C4),.CI(C3),.DI(A[4]),.S(I[4]) );
|
||||
MUXCY_L MUXCY_L5 (.LO(C5),.CI(C4),.DI(A[5]),.S(I[5]) );
|
||||
MUXCY_D MUXCY_D6 (.LO(C6),.O(C6O),.CI(C5),.DI(A[6]),.S(I[6]) );
|
||||
MUXCY MUXCY_7 (.O(CO),.CI(C6),.DI(A[7]),.S(I[7]) );
|
||||
XORCY XORCY0 (.O(S[0]),.CI(CI),.LI(I[0]));
|
||||
XORCY XORCY1 (.O(S[1]),.CI(C0),.LI(I[1]));
|
||||
XORCY XORCY2 (.O(S[2]),.CI(C1),.LI(I[2]));
|
||||
XORCY XORCY3 (.O(S[3]),.CI(C2),.LI(I[3]));
|
||||
XORCY XORCY4 (.O(S[4]),.CI(C3),.LI(I[4]));
|
||||
XORCY XORCY5 (.O(S[5]),.CI(C4),.LI(I[5]));
|
||||
XORCY XORCY6 (.O(S[6]),.CI(C5),.LI(I[6]));
|
||||
XORCY XORCY7 (.O(S[7]),.CI(C6),.LI(I[7]));
|
||||
XOR2 X1(.O(OFL),.I0(C6O),.I1(CO));
|
||||
endmodule
|
||||
|
||||
module NewAlu(input [10:0] OP, // ALU Operation
|
||||
input [7:0] A, // Registers input
|
||||
input [7:0] X, // ""
|
||||
input [7:0] Y, // ""
|
||||
input [7:0] S, // ""
|
||||
input [7:0] M, // Secondary input to ALU
|
||||
input [7:0] T, // Secondary input to ALU
|
||||
// -- Flags Input
|
||||
input CI, // Carry In
|
||||
input VI, // Overflow In
|
||||
// -- Flags output
|
||||
output reg CO, // Carry out
|
||||
output reg VO, // Overflow out
|
||||
output reg SO, // Sign out
|
||||
output reg ZO, // zero out
|
||||
// -- Result output
|
||||
output reg [7:0] Result,// Result out
|
||||
output reg [7:0] IntR); // Intermediate result out
|
||||
// Crack the ALU Operation
|
||||
wire [1:0] o_left_input, o_right_input;
|
||||
wire [2:0] o_first_op, o_second_op;
|
||||
wire o_fc;
|
||||
assign {o_left_input, o_right_input, o_first_op, o_second_op, o_fc} = OP;
|
||||
|
||||
// Determine left, right inputs to Add/Sub ALU.
|
||||
reg [7:0] L, R;
|
||||
reg CR;
|
||||
always begin
|
||||
casez(o_left_input)
|
||||
0: L = A;
|
||||
1: L = Y;
|
||||
2: L = X;
|
||||
3: L = A & X;
|
||||
endcase
|
||||
casez(o_right_input)
|
||||
0: R = M;
|
||||
1: R = T;
|
||||
2: R = L;
|
||||
3: R = S;
|
||||
endcase
|
||||
CR = CI;
|
||||
casez(o_first_op[2:1])
|
||||
0: {CR, IntR} = {R, CI & o_first_op[0]}; // SHL, ROL
|
||||
1: {IntR, CR} = {CI & o_first_op[0], R}; // SHR, ROR
|
||||
2: IntR = R; // Passthrough
|
||||
3: IntR = R + (o_first_op[0] ? 8'b1 : 8'b11111111); // INC/DEC
|
||||
endcase
|
||||
end
|
||||
wire [7:0] AddR;
|
||||
wire AddCO, AddVO;
|
||||
MyAddSub addsub(.A(L),.B(IntR),.CI(o_second_op[0] ? CR : 1'b1),.ADD(!o_second_op[2]), .S(AddR), .CO(AddCO), .OFL(AddVO));
|
||||
// Produce the output of the second stage.
|
||||
always begin
|
||||
casez(o_second_op)
|
||||
0: {CO, Result} = {CR, L | IntR};
|
||||
1: {CO, Result} = {CR, L & IntR};
|
||||
2: {CO, Result} = {CR, L ^ IntR};
|
||||
3, 6, 7: {CO, Result} = {AddCO, AddR};
|
||||
4, 5: {CO, Result} = {CR, IntR};
|
||||
endcase
|
||||
// Final result
|
||||
ZO = (Result == 0);
|
||||
// Compute overflow flag
|
||||
VO = VI;
|
||||
casez(o_second_op)
|
||||
1: if (!o_fc) VO = IntR[6]; // Set V to 6th bit for BIT
|
||||
3: VO = AddVO; // ADC always sets V
|
||||
7: if (o_fc) VO = AddVO; // Only SBC sets V.
|
||||
endcase
|
||||
// Compute sign flag. It's always the uppermost bit of the result,
|
||||
// except for BIT that sets it to the 7th input bit
|
||||
SO = (o_second_op == 1 && !o_fc) ? IntR[7] : Result[7];
|
||||
end
|
||||
endmodule
|
||||
|
||||
module AddressGenerator(input clk, input ce,
|
||||
input [4:0] Operation,
|
||||
input [1:0] MuxCtrl,
|
||||
input [7:0] DataBus, T, X, Y,
|
||||
output [15:0] AX,
|
||||
output Carry);
|
||||
// Actual contents of registers
|
||||
reg [7:0] AL, AH;
|
||||
// Last operation generated a carry?
|
||||
reg SavedCarry;
|
||||
assign AX = {AH, AL};
|
||||
|
||||
wire [2:0] ALCtrl = Operation[4:2];
|
||||
wire [1:0] AHCtrl = Operation[1:0];
|
||||
|
||||
// Possible new value for AL.
|
||||
wire [7:0] NewAL;
|
||||
assign {Carry,NewAL} = {1'b0, (MuxCtrl[1] ? T : AL)} + {1'b0, (MuxCtrl[0] ? Y : X)};
|
||||
|
||||
// The other one
|
||||
wire TmpVal = (!AHCtrl[1] | SavedCarry);
|
||||
wire [7:0] TmpAdd = (AHCtrl[1] ? AH : AL) + {7'b0, TmpVal};
|
||||
|
||||
always @(posedge clk) if (ce) begin
|
||||
SavedCarry <= Carry;
|
||||
if (ALCtrl[2])
|
||||
case(ALCtrl[1:0])
|
||||
0: AL <= NewAL;
|
||||
1: AL <= DataBus;
|
||||
2: AL <= TmpAdd;
|
||||
3: AL <= T;
|
||||
endcase
|
||||
|
||||
case(AHCtrl[1:0])
|
||||
0: AH <= AH;
|
||||
1: AH <= 0;
|
||||
2: AH <= TmpAdd;
|
||||
3: AH <= DataBus;
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
|
||||
module ProgramCounter(input clk, input ce,
|
||||
input [1:0] LoadPC,
|
||||
input GotInterrupt,
|
||||
input [7:0] DIN,
|
||||
input [7:0] T,
|
||||
output reg [15:0] PC, output JumpNoOverflow);
|
||||
reg [15:0] NewPC;
|
||||
assign JumpNoOverflow = ((PC[8] ^ NewPC[8]) == 0) & LoadPC[0] & LoadPC[1];
|
||||
|
||||
always begin
|
||||
// Load PC Control
|
||||
case (LoadPC)
|
||||
0,1: NewPC = PC + {15'b0, (LoadPC[0] & ~GotInterrupt)};
|
||||
2: NewPC = {DIN,T};
|
||||
3: NewPC = PC + {{8{T[7]}},T};
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
if (ce)
|
||||
PC <= NewPC;
|
||||
endmodule
|
||||
|
||||
|
||||
module CPU(input clk, input ce, input reset,
|
||||
input [7:0] DIN,
|
||||
input irq,
|
||||
input nmi,
|
||||
output reg [7:0] dout, output reg [15:0] aout,
|
||||
output reg mr,
|
||||
output reg mw);
|
||||
reg [7:0] A, X, Y;
|
||||
reg [7:0] SP, T, P;
|
||||
reg [7:0] IR;
|
||||
reg [2:0] State;
|
||||
reg GotInterrupt;
|
||||
|
||||
reg IsResetInterrupt;
|
||||
wire [15:0] PC;
|
||||
reg JumpTaken;
|
||||
wire JumpNoOverflow;
|
||||
|
||||
// De-multiplex microcode
|
||||
wire [37:0] MicroCode;
|
||||
wire [1:0] LoadSP = MicroCode[1:0]; // 7 LUT
|
||||
wire [1:0] LoadPC = MicroCode[3:2]; // 12 LUT
|
||||
wire [1:0] AddrBus = MicroCode[5:4]; // 18 LUT
|
||||
wire [2:0] MemWrite = MicroCode[8:6]; // 10 LUT
|
||||
wire [4:0] AddrCtrl = MicroCode[13:9];
|
||||
wire FlagCtrl = MicroCode[14]; // RegWrite + FlagCtrl = 22 LUT
|
||||
wire [1:0] LoadT = MicroCode[16:15]; // 13 LUT
|
||||
wire [1:0] StateCtrl = MicroCode[18:17];
|
||||
wire [2:0] FlagsCtrl = MicroCode[21:19];
|
||||
wire [15:0] IrFlags = MicroCode[37:22];
|
||||
|
||||
// Load Instruction Register? Force BRK on Interrupt.
|
||||
wire [7:0] NextIR = (State == 0) ? (GotInterrupt ? 8'd0 : DIN) : IR;
|
||||
wire IsBranchCycle1 = (IR[4:0] == 5'b10000) && State[0];
|
||||
|
||||
// Compute next state.
|
||||
reg [2:0] NextState;
|
||||
always begin
|
||||
case (StateCtrl)
|
||||
0: NextState = State + 3'd1;
|
||||
1: NextState = (AXCarry ? 3'd4 : 3'd5);
|
||||
2: NextState = (IsBranchCycle1 && JumpTaken) ? 2 : 0; // Override next state if the branch is taken.
|
||||
3: NextState = (JumpNoOverflow ? 3'd0 : 3'd4);
|
||||
endcase
|
||||
end
|
||||
|
||||
wire [15:0] AX;
|
||||
wire AXCarry;
|
||||
AddressGenerator addgen(clk, ce, AddrCtrl, {IrFlags[0], IrFlags[1]}, DIN, T, X, Y, AX, AXCarry);
|
||||
|
||||
// Microcode table has a 1 clock latency (block ram).
|
||||
MicroCodeTable micro2(clk, ce, reset, NextIR, NextState, MicroCode);
|
||||
|
||||
wire [7:0] AluR;
|
||||
wire [7:0] AluIntR;
|
||||
wire CO, VO, SO,ZO;
|
||||
NewAlu new_alu(IrFlags[15:5], A,X,Y,SP,DIN,T, P[0], P[6], CO, VO, SO, ZO, AluR, AluIntR);
|
||||
|
||||
// Registers
|
||||
always @(posedge clk) if (reset) begin
|
||||
A <= 0;
|
||||
X <= 0;
|
||||
Y <= 0;
|
||||
end else if (ce) begin
|
||||
if (FlagCtrl & IrFlags[2]) X <= AluR;
|
||||
if (FlagCtrl & IrFlags[3]) A <= AluR;
|
||||
if (FlagCtrl & IrFlags[4]) Y <= AluR;
|
||||
end
|
||||
|
||||
// Program counter
|
||||
ProgramCounter pc(clk, ce, LoadPC, GotInterrupt, DIN, T, PC, JumpNoOverflow);
|
||||
|
||||
reg IsNMIInterrupt;
|
||||
reg LastNMI;
|
||||
// NMI is triggered at any time, except during reset, or when we're in the middle of
|
||||
// reading the vector address
|
||||
wire turn_nmi_on = (AddrBus != 3) && !IsResetInterrupt && nmi && !LastNMI;
|
||||
// Controls whether we'll remember the state in LastNMI
|
||||
wire nmi_remembered = (AddrBus != 3) && !IsResetInterrupt ? nmi : LastNMI;
|
||||
// NMI flag is cleared right after we read the vector address
|
||||
wire turn_nmi_off = (AddrBus == 3) && (State[0] == 0);
|
||||
// Controls whether IsNmiInterrupt will get set
|
||||
wire nmi_active = turn_nmi_on ? 1 : turn_nmi_off ? 0 : IsNMIInterrupt;
|
||||
always @(posedge clk) begin
|
||||
if (reset) begin
|
||||
IsNMIInterrupt <= 0;
|
||||
LastNMI <= 0;
|
||||
end else if (ce) begin
|
||||
IsNMIInterrupt <= nmi_active;
|
||||
LastNMI <= nmi_remembered;
|
||||
end
|
||||
end
|
||||
|
||||
// Generate outputs from module...
|
||||
always begin
|
||||
dout = 8'bX;
|
||||
case (MemWrite[1:0])
|
||||
'b00: dout = T;
|
||||
'b01: dout = AluR;
|
||||
'b10: dout = {P[7:6], 1'b1, !GotInterrupt, P[3:0]};
|
||||
'b11: dout = State[0] ? PC[7:0] : PC[15:8];
|
||||
endcase
|
||||
mw = MemWrite[2] && !IsResetInterrupt; // Prevent writing while handling a reset
|
||||
mr = !mw;
|
||||
end
|
||||
|
||||
always begin
|
||||
case (AddrBus)
|
||||
0: aout = PC;
|
||||
1: aout = AX;
|
||||
2: aout = {8'h01, SP};
|
||||
// irq/BRK vector FFFE
|
||||
// nmi vector FFFA
|
||||
// Reset vector FFFC
|
||||
3: aout = {13'b1111_1111_1111_1, !IsNMIInterrupt, !IsResetInterrupt, ~State[0]};
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (reset) begin
|
||||
// Reset runs the BRK instruction as usual.
|
||||
State <= 0;
|
||||
IR <= 0;
|
||||
GotInterrupt <= 1;
|
||||
IsResetInterrupt <= 1;
|
||||
P <= 'h24;
|
||||
SP <= 0;
|
||||
T <= 0;
|
||||
JumpTaken <= 0;
|
||||
end else if (ce) begin
|
||||
// Stack pointer control.
|
||||
// The operand is an optimization that either
|
||||
// returns -1,0,1 depending on LoadSP
|
||||
case (LoadSP)
|
||||
0,2,3: SP <= SP + { {7{LoadSP[0]}}, LoadSP[1] };
|
||||
1: SP <= X;
|
||||
endcase
|
||||
|
||||
// LoadT control
|
||||
case (LoadT)
|
||||
2: T <= DIN;
|
||||
3: T <= AluIntR;
|
||||
endcase
|
||||
|
||||
if (FlagCtrl) begin
|
||||
case(FlagsCtrl)
|
||||
0: P <= P; // No Op
|
||||
1: {P[0], P[1], P[6], P[7]} <= {CO, ZO, VO, SO}; // ALU
|
||||
2: P[2] <= 1; // BRK
|
||||
3: P[6] <= 0; // CLV
|
||||
4: {P[7:6],P[3:0]} <= {DIN[7:6], DIN[3:0]}; // RTI/PLP
|
||||
5: P[0] <= IR[5]; // CLC/SEC
|
||||
6: P[2] <= IR[5]; // CLI/SEI
|
||||
7: P[3] <= IR[5]; // CLD/SED
|
||||
endcase
|
||||
end
|
||||
|
||||
// Compute if the jump is to be taken. Result is stored in a flipflop, so
|
||||
// it won't be available until next cycle.
|
||||
// NOTE: Using DIN here. DIN is IR at cycle 0. This means JumpTaken will
|
||||
// contain the Jump status at cycle 1.
|
||||
case (DIN[7:5])
|
||||
0: JumpTaken <= ~P[7]; // BPL
|
||||
1: JumpTaken <= P[7]; // BMI
|
||||
2: JumpTaken <= ~P[6]; // BVC
|
||||
3: JumpTaken <= P[6]; // BVS
|
||||
4: JumpTaken <= ~P[0]; // BCC
|
||||
5: JumpTaken <= P[0]; // BCS
|
||||
6: JumpTaken <= ~P[1]; // BNE
|
||||
7: JumpTaken <= P[1]; // BEQ
|
||||
endcase
|
||||
|
||||
// Check the interrupt status on the last cycle of the current instruction,
|
||||
// (or on cycle #1 of any branch instruction)
|
||||
if (StateCtrl == 2'b10) begin
|
||||
GotInterrupt <= (irq & ~P[2]) | nmi_active;
|
||||
IsResetInterrupt <= 0;
|
||||
end
|
||||
|
||||
IR <= NextIR;
|
||||
State <= NextState;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
@@ -160,7 +160,7 @@ module NES(input clk, input reset, input ce,
|
||||
if (reset)
|
||||
cpu_cycle_counter <= 0;
|
||||
else if (ce)
|
||||
cpu_cycle_counter <= (cpu_cycle_counter == 2) ? 0 : cpu_cycle_counter + 1;
|
||||
cpu_cycle_counter <= (cpu_cycle_counter == 2) ? 2'd0 : cpu_cycle_counter + 1'd1;
|
||||
end
|
||||
|
||||
// Sample the NMI flag on cycle #0, otherwise if NMI happens on cycle #0 or #1,
|
||||
@@ -174,7 +174,7 @@ module NES(input clk, input reset, input ce,
|
||||
nmi_active <= nmi;
|
||||
end
|
||||
|
||||
wire apu_ce = ce && (cpu_cycle_counter == 2);
|
||||
wire apu_ce = ce && (cpu_cycle_counter == 2);
|
||||
|
||||
// -- CPU
|
||||
wire [15:0] cpu_addr;
|
||||
@@ -182,7 +182,8 @@ module NES(input clk, input reset, input ce,
|
||||
wire pause_cpu;
|
||||
reg apu_irq_delayed;
|
||||
reg mapper_irq_delayed;
|
||||
T65 cpu
|
||||
|
||||
T65 cpu
|
||||
(
|
||||
.mode(0),
|
||||
.BCD_en(0),
|
||||
@@ -199,6 +200,8 @@ module NES(input clk, input reset, input ce,
|
||||
.DI(cpu_rnw ? from_data_bus : cpu_dout),
|
||||
.DO(cpu_dout)
|
||||
);
|
||||
|
||||
|
||||
// -- DMA
|
||||
wire [15:0] dma_aout;
|
||||
wire dma_aout_enable;
|
||||
@@ -217,7 +220,7 @@ module NES(input clk, input reset, input ce,
|
||||
odd_or_even, // Even or odd cycle
|
||||
(addr == 'h4014 && mw_int), // Sprite trigger
|
||||
apu_dma_request, // DMC Trigger
|
||||
cpu_rnw, // CPU in a read cycle?
|
||||
cpu_rnw, // CPU in a read cycle?
|
||||
cpu_dout, // Data from cpu
|
||||
from_data_bus, // Data from RAM etc.
|
||||
apu_dma_addr, // DMC addr
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright (c) 2012-2013 Ludvig Strigeus
|
||||
// This program is GPL Licensed. See COPYING for the full license.
|
||||
|
||||
// altera message_off 10935
|
||||
|
||||
// Module handles updating the loopy scroll register
|
||||
module LoopyGen (
|
||||
input clk, input ce,
|
||||
@@ -35,19 +37,19 @@ module LoopyGen (
|
||||
if (is_rendering) begin
|
||||
// Increment course X scroll right after attribute table byte was fetched.
|
||||
if (cycle[2:0] == 3 && (cycle < 256 || cycle >= 320 && cycle < 336)) begin
|
||||
loopy_v[4:0] <= loopy_v[4:0] + 1;
|
||||
loopy_v[4:0] <= loopy_v[4:0] + 1'd1;
|
||||
loopy_v[10] <= loopy_v[10] ^ (loopy_v[4:0] == 31);
|
||||
end
|
||||
|
||||
// Vertical Increment
|
||||
if (cycle == 251) begin
|
||||
loopy_v[14:12] <= loopy_v[14:12] + 1;
|
||||
loopy_v[14:12] <= loopy_v[14:12] + 1'd1;
|
||||
if (loopy_v[14:12] == 7) begin
|
||||
if (loopy_v[9:5] == 29) begin
|
||||
loopy_v[9:5] <= 0;
|
||||
loopy_v[11] <= !loopy_v[11];
|
||||
end else begin
|
||||
loopy_v[9:5] <= loopy_v[9:5] + 1;
|
||||
loopy_v[9:5] <= loopy_v[9:5] + 1'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -88,7 +90,7 @@ module LoopyGen (
|
||||
ppu_address_latch <= 0; //Reset PPU address latch
|
||||
end else if ((read || write) && ain == 7 && !is_rendering) begin
|
||||
// Increment address every time we accessed a reg
|
||||
loopy_v <= loopy_v + (ppu_incr ? 32 : 1);
|
||||
loopy_v <= loopy_v + (ppu_incr ? 15'd32 : 15'd1);
|
||||
end
|
||||
end
|
||||
assign loopy = loopy_v;
|
||||
@@ -127,7 +129,7 @@ module ClockGen(input clk, input ce, input reset,
|
||||
cycle <= 0;
|
||||
is_in_vblank <= 1;
|
||||
end else if (ce) begin
|
||||
cycle <= end_of_line ? 0 : cycle + 1;
|
||||
cycle <= end_of_line ? 1'd0 : cycle + 1'd1;
|
||||
is_in_vblank <= new_is_in_vblank;
|
||||
end
|
||||
// always @(posedge clk) if (ce) begin
|
||||
@@ -140,12 +142,11 @@ module ClockGen(input clk, input ce, input reset,
|
||||
second_frame <= 0;
|
||||
end else if (ce && end_of_line) begin
|
||||
// Once the scanline counter reaches end of 260, it gets reset to -1.
|
||||
scanline <= exiting_vblank ? 9'b111111111 : scanline + 1;
|
||||
scanline <= exiting_vblank ? 9'b111111111 : scanline + 1'd1;
|
||||
// The pre render flag is set while we're on scanline -1.
|
||||
is_pre_render <= exiting_vblank;
|
||||
|
||||
if (exiting_vblank)
|
||||
second_frame <= !second_frame;
|
||||
//if (exiting_vblank) second_frame <= !second_frame;
|
||||
end
|
||||
|
||||
endmodule // ClockGen
|
||||
@@ -228,11 +229,12 @@ module SpriteRAM(input clk, input ce,
|
||||
output reg spr_overflow, // Set to true if we had more than 8 objects on a scan line. Reset when exiting vblank.
|
||||
output reg sprite0); // True if sprite#0 is included on the scan line currently being painted.
|
||||
reg [7:0] sprtemp[0:31]; // Sprite Temporary Memory. 32 bytes.
|
||||
reg [7:0] oam[0:255]; // Sprite OAM. 256 bytes.
|
||||
reg [7:0] oam_ptr; // Pointer into oam_ptr.
|
||||
reg [2:0] p; // Upper 3 bits of pointer into temp, the lower bits are oam_ptr[1:0].
|
||||
reg [1:0] state; // Current state machine state
|
||||
wire [7:0] oam_data = oam[oam_ptr];
|
||||
reg [7:0] oam[256]; // Sprite OAM. 256 bytes.
|
||||
reg [7:0] oam_data;
|
||||
|
||||
// Compute the current address we read/write in sprtemp.
|
||||
reg [4:0] sprtemp_ptr;
|
||||
// Check if the current Y coordinate is inside.
|
||||
@@ -282,13 +284,18 @@ module SpriteRAM(input clk, input ce,
|
||||
new_oam_ptr[1:0] = oam_ptr[1:0] + {1'b0, oam_inc[0]};
|
||||
{oam_wrapped, new_oam_ptr[7:2]} = {1'b0, oam_ptr[7:2]} + {6'b0, oam_inc[1]};
|
||||
end
|
||||
|
||||
wire [7:0] oam_ptr_tmp = oam_ptr_load ? data_in : new_oam_ptr;
|
||||
always @(posedge clk) if (ce) begin
|
||||
|
||||
// Some bits of the OAM are hardwired to zero.
|
||||
if (oam_load)
|
||||
oam[oam_ptr] <= (oam_ptr & 3) == 2 ? data_in & 8'hE3: data_in;
|
||||
if (cycle[0] && sprites_enabled || oam_load || oam_ptr_load) begin
|
||||
oam_ptr <= oam_ptr_load ? data_in : new_oam_ptr;
|
||||
if (oam_load) begin
|
||||
oam[oam_ptr] <= (oam_ptr & 3) == 2 ? data_in & 8'hE3: data_in;
|
||||
oam_data <= (oam_ptr & 3) == 2 ? data_in & 8'hE3: data_in;
|
||||
end
|
||||
if((cycle[0] && sprites_enabled) || oam_load || oam_ptr_load) begin
|
||||
oam_ptr <= oam_ptr_tmp;
|
||||
oam_data <= oam[oam_ptr_tmp];
|
||||
end
|
||||
// Set overflow flag?
|
||||
if (sprites_enabled && state == 2'b11 && spr_is_inside)
|
||||
@@ -305,7 +312,7 @@ module SpriteRAM(input clk, input ce,
|
||||
// Update state machine on every second cycle.
|
||||
if (cycle[0]) begin
|
||||
// Increment p whenever oam_ptr carries in state 0 or 1.
|
||||
if (!state[1] && oam_ptr[1:0] == 2'b11) p <= p + 1;
|
||||
if (!state[1] && oam_ptr[1:0] == 2'b11) p <= p + 1'd1;
|
||||
// Set sprite0 if sprite1 was included on the scan line
|
||||
casez({state, (p == 7) && (oam_ptr[1:0] == 2'b11), oam_wrapped})
|
||||
4'b00_0_?: state <= 2'b00; // State #0: Keep filling
|
||||
@@ -322,6 +329,7 @@ module SpriteRAM(input clk, input ce,
|
||||
state <= 0;
|
||||
p <= 0;
|
||||
oam_ptr <= 0;
|
||||
oam_data <= oam[0];
|
||||
sprite0_curr <= 0;
|
||||
sprite0 <= sprite0_curr;
|
||||
end
|
||||
@@ -355,7 +363,7 @@ module SpriteAddressGen(input clk, input ce,
|
||||
wire load_pix2 = (cycle == 7) && enabled;
|
||||
reg dummy_sprite; // Set if attrib indicates the sprite is invalid.
|
||||
// Flip incoming vram data based on flipx. Zero out the sprite if it's invalid. The bits are already flipped once.
|
||||
wire [7:0] vram_f = dummy_sprite ? 0 :
|
||||
wire [7:0] vram_f = dummy_sprite ? 8'd0 :
|
||||
!flip_x ? {vram_data[0], vram_data[1], vram_data[2], vram_data[3], vram_data[4], vram_data[5], vram_data[6], vram_data[7]} :
|
||||
vram_data;
|
||||
wire [3:0] y_f = temp_y ^ {flip_y, flip_y, flip_y, flip_y};
|
||||
@@ -679,7 +687,7 @@ module PPU(input clk, input ce, input reset, // input clock 21.48 MHz / 4. 1
|
||||
always @(posedge clk) if (ce) begin
|
||||
if (vram_read_delayed)
|
||||
vram_latch <= vram_din;
|
||||
vram_read_delayed = vram_r;
|
||||
vram_read_delayed <= vram_r;
|
||||
end
|
||||
|
||||
// Value currently being written to video ram
|
||||
|
||||
Reference in New Issue
Block a user