Skip to content

Commit 97becc2

Browse files
committed
Enhance Tetris simulation and RNG handling in tetris6x6 module
- Added a check to ensure a random number generator is present in the simulation, preventing constant-folding issues. - Updated game logic to improve piece movement and rotation mechanics, ensuring proper gameplay flow. - Enhanced the game-over detection and row validation to ensure accurate game state representation. - Refactored comments for clarity and updated the reset signal handling in the Verilog module for better functionality.
1 parent 6fd437c commit 97becc2

2 files changed

Lines changed: 84 additions & 17 deletions

File tree

test/0031.tetris6x6/tetris6x6.v

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ module tetris6x6 (
3434
// For pe_synth's internal $random lowering: provide an active-low reset signal name.
3535
wire rst_n;
3636
assign rst_n = ~rst;
37-
wire [1:0] rand2;
38-
assign rand2 = $random;
37+
reg [1:0] rand2;
38+
always @(posedge clk or negedge rst_n) begin
39+
if (!rst_n) rand2 <= 2'd0;
40+
else rand2 <= $random;
41+
end
3942

4043
// FSM: 0=PLAY, 1=CLEAR, 2=SPAWN
4144
reg [1:0] state;

test/0031.tetris6x6/tetris6x6_pe_sim_o4_smoke.cc

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,21 @@ int main()
177177
throw std::runtime_error("pe_synth failed: " + std::string(reinterpret_cast<char const*>(err.message.data()), err.message.size()));
178178
}
179179

180+
// Ensure `$random` lowered to a PE RNG macro (otherwise it may constant-fold and always spawn I).
181+
{
182+
bool has_rng{};
183+
for(auto& blk : nl.models)
184+
{
185+
for(auto* m = blk.begin; m != blk.curr; ++m)
186+
{
187+
if(m->type != ::phy_engine::model::model_type::normal) { continue; }
188+
if(m->ptr == nullptr) { continue; }
189+
if(m->ptr->get_model_name() == ::fast_io::u8string_view{u8"RANDOM_GENERATOR4"}) { has_rng = true; }
190+
}
191+
}
192+
if(!has_rng) { return 12; }
193+
}
194+
180195
if(!c.analyze()) { return 12; }
181196

182197
auto* in_clk = input_by_name.at("clk");
@@ -244,21 +259,70 @@ int main()
244259
if(read_row(y) != 0) { return 15; }
245260
}
246261

247-
// 2) Rotate should rotate the first I piece in-place (no fall due to priority).
262+
// 2) Move right once, then rotate to place a vertical obstacle column at x=2.
263+
set_in(in_right, true);
264+
set_in(in_clk, false);
265+
c.digital_clk();
266+
tick();
267+
set_in(in_right, false);
268+
set_in(in_clk, false);
269+
c.digital_clk();
270+
if(read_port_bit(*game_over_port)) { return 16; }
271+
if(read_row(0) != 0b111100) { return 17; } // I moved right (px=2)
272+
248273
set_in(in_rotate, true);
249274
set_in(in_clk, false);
250275
c.digital_clk();
251276
tick();
252277
set_in(in_rotate, false);
253278
set_in(in_clk, false);
254279
c.digital_clk();
255-
if(read_port_bit(*game_over_port)) { return 16; }
256-
if(read_row(0) != 0b000010) { return 17; }
257-
if(read_row(1) != 0b000010) { return 18; }
258-
if(read_row(2) != 0b000010) { return 19; }
259-
if(read_row(3) != 0b000010) { return 20; }
280+
if(read_port_bit(*game_over_port)) { return 18; }
281+
if(read_row(0) != 0b000100) { return 19; }
282+
if(read_row(1) != 0b000100) { return 20; }
283+
if(read_row(2) != 0b000100) { return 21; }
284+
if(read_row(3) != 0b000100) { return 22; }
285+
286+
// 3) Let the vertical I fall and lock at the bottom (obstacle at rows2..5, x=2).
287+
set_in(in_left, false);
288+
set_in(in_right, false);
289+
set_in(in_rotate, false);
290+
tick(); // py=1
291+
tick(); // py=2
292+
tick(); // lock -> CLEAR
293+
294+
if(read_row(0) != 0) { return 23; }
295+
if(read_row(1) != 0) { return 24; }
296+
if(read_row(2) != 0b000100) { return 25; }
297+
if(read_row(3) != 0b000100) { return 26; }
298+
if(read_row(4) != 0b000100) { return 27; }
299+
if(read_row(5) != 0b000100) { return 28; }
300+
301+
// 4) Spawn one more piece and ensure it does not overlap ("phase") into the obstacle column.
302+
// (All pieces overlap bit2 at spawn, so collide_down should stop them above row2.)
303+
{
304+
bool saw_spawn{};
305+
for(std::size_t i{}; i < 256; ++i)
306+
{
307+
tick();
308+
if(read_port_bit(*game_over_port)) { return 29; }
309+
if(read_row(0) != 0)
310+
{
311+
saw_spawn = true;
312+
break;
313+
}
314+
}
315+
if(!saw_spawn) { return 30; }
316+
317+
tick(); // py=1
318+
tick(); // collide_down -> lock
319+
if(read_row(2) != 0b000100) { return 31; }
320+
if(read_row(3) != 0b000100) { return 32; }
321+
if(read_row(4) != 0b000100) { return 33; }
322+
if(read_row(5) != 0b000100) { return 34; }
323+
}
260324

261-
// 3) Run until game_over and check the "X" overlay.
325+
// 5) Run until game_over and check the "X" overlay.
262326
set_in(in_left, false);
263327
set_in(in_rotate, false);
264328
set_in(in_right, true); // bias towards a quick loss
@@ -273,14 +337,14 @@ int main()
273337
break;
274338
}
275339
}
276-
if(!saw_game_over) { return 21; }
277-
278-
if(read_row(0) != 0b100001) { return 22; }
279-
if(read_row(1) != 0b010010) { return 23; }
280-
if(read_row(2) != 0b001100) { return 24; }
281-
if(read_row(3) != 0b001100) { return 25; }
282-
if(read_row(4) != 0b010010) { return 26; }
283-
if(read_row(5) != 0b100001) { return 27; }
340+
if(!saw_game_over) { return 36; }
341+
342+
if(read_row(0) != 0b100001) { return 37; }
343+
if(read_row(1) != 0b010010) { return 38; }
344+
if(read_row(2) != 0b001100) { return 39; }
345+
if(read_row(3) != 0b001100) { return 40; }
346+
if(read_row(4) != 0b010010) { return 41; }
347+
if(read_row(5) != 0b100001) { return 42; }
284348

285349
// 4) Gate count check (after passing the sim checks), under O4 optimization.
286350
{

0 commit comments

Comments
 (0)