1
0
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:
Sebastien Delestaing
2018-12-10 21:34:22 +01:00
parent d97f32f001
commit 3162e9ed2b
5 changed files with 111 additions and 490 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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