Tecmo Super Bowl
Tecmo's 1991 NFL game, read here in its US NES release through bruddog's commented disassembly.
On this page
The atlas reads Tecmo Super Bowl’s US NES release through bruddog’s commented asm6f disassembly, which grew from jstout’s earlier one. Built with the ROM’s graphics, its program code matches the ROM’s byte for byte. Labels and comments quoted here are bruddog’s. Nothing has been measured in the ROM yet.
Each rating is one of 16 steps, shown as 6 to 1001, moved up or down by the player’s condition. The max speed rating gives a max speed of 21 to 36 on offense and 37 to 52 on defense2, so at the same rating a defender’s cap is higher than an offensive player’s; running speed sets the starting speed and rushing power how often it rises2.
At each snap the defense’s play comes from a table keyed by the offense’s play id and the defense’s slot. Calling the column of the play’s group, which a playbook set on the playbook screen makes the offense’s own slot, is the only way to get one of 11 guess-only defensive plays3. Some of their scripts, such as reaction 128, set the top running-speed step and add 48 more max speed and 48 more HP4 before the player rushes. A computer defense picks a slot at random, except on short third and fourth downs, where it calls a run slot 80% of the time (computed) with 3 yards or less to go5. As the atlas reads it, the check meant to favor pass defense on long yardage compares the wrong byte, so it never fires5.
When two players lock up, hitting power decides between computer players, with random holds and rolls6. A human player against a computer one mashes A and needs 2 A presses in a 64-frame hold7, unless a large enough hitting-power lead throws the computer player at once7.
A pass adds the passer’s pass control to the receiver’s reception, and each nearby defender subtracts his interception value before a random roll; the thresholds give a catch at 79 or more uncovered and an interception under 51 covered8. When the target isn’t near the ball, the interception check reads a leftover script argument in place of the passer’s value, which the disassembly calls a major bug9.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Player ratings | Steps into tables | 16 steps per rating, shown as 6 to 100, moved by condition; separate speed tables for offense and defense |
| Play calling | Slot pairing | 8 slots a side; the defense's slot matching the play's group gets one of 11 defensive plays, some with boosted rushers |
| Button mashing | Press count | a human needs 2 A presses in a 64-frame hold to beat a computer player, unless 32 more HP wins at once |
| Pass completion | Ratings roll | PC plus REC less each defender's INT scales a random roll against fixed catch and interception lines |
Every claim about this game, by concept (9)
References
- ^Tecmo Super Bowl stores each player rating as a 4-bit index from 0 to 15, two to a byte. The player data screen shows an index as 6, 13, 19, 25, 31, 38, 44, 50, 56, 63, 69, 75, 81, 88, 94, or 100. When the game reads a rating, it adds the player's condition (bad 0, average 1, good 2, excellent 3) less 1 and clamps the result to 0–15, so a bad player plays one step down and an excellent one two steps up.Codebruddog/Tecmo_Super_Bowl_NES_Disassembly
How we know
5039@get_player_skill: ; GET PLAYER SKILL(Y=STARTER ID, A = SKILL TO GET) ⋮ 5042 LSR ; SHIFT RIGHT SINCE TWO SKILLS PER BYTE ⋮ 5045 BCS @save_skill_value ; SKILL IN SECOND NIBBLE? YES-> SKILL IS IN SECOND NIBBLE OF BYTE ⋮ 5049 AND #$0F ; MASK OUT UPPER NIBBLE
Bank31_fixed_bank.asm lines 5039–5050 at f3bae0e · upstream ↗ 5063@add_condition_to_skill: ; UPDATE PLAYER SKILL VALUE BASED ON CONDITION ⋮ 5066 CLC ; FINAL SKILL INDEX= SKILL VALUE INDEX + PLAYER CONDITION 5067 ADC player_addr ; 5068 SEC ; SET FINAL SKILL INDEX = 0, IF FINAL SKILL INDEX <0 5069 SBC #$01 ; ⋮ 5073 CMP #MAX_SKILL + 1 ; SET FINAL SKILL INDEX = 0X0F, IF FINAL SKILL INDEX >0X0F
Bank31_fixed_bank.asm lines 5063–5075 at f3bae0e · upstream ↗ 128BAD_CONDITION = $00 129AVERAGE_CONDITION = $01 130GOOD_CONDITION = $02 131EXCELLENT_CONDITION = $03
constants_variables/constants.asm lines 128–131 at f3bae0e · upstream ↗ 2726SKILL_NUMBER_VALUE_TABLE: ; SKILL VALUES 2727 .WORD $0006, $0013, $0019, $0025, $0031, $0038, $0044, $0050 2728 .WORD $0056, $0063, $0069, $0075, $0081, $0088, $0094, $0100
Bank25_leaders_player_data_pro_bowl_abbrev.asm lines 2726–2728 at f3bae0e · upstream ↗ 2245@draw_skill_number: 2246 LDA skill_value ; LOAD SKILL INDEX 2247 ASL ; SHIFT SINCE EACH ENTRY IS TWO DIGITS 2248 TAY ; LOAD FIRST DIGIT FROM SKILL VALUES 2249 LDA SKILL_NUMBER_VALUE_TABLE+1,Y ;
Bank25_leaders_player_data_pro_bowl_abbrev.asm lines 2245–2249 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abOn the field each player carries a current speed and a max speed. The max speed (MS) rating picks a max speed of 21 to 36 for an offensive player and 37 to 52 for a defender, one per step. Running speed (RS) sets the starting current speed, 14 to 29, and rushing power (RP) sets a countdown of 13 frames at step 0 down to 1 at steps 14 and 15. On each frame a player is moving, the countdown drops by 1; when it reaches 0 it reloads, and the current speed rises by 1 unless it has reached max speed. A computer-controlled defense facing a human-controlled offense loads differently: it adds
CPU_DEF_MS_BOOSTto its max speed and to its RS and RP steps, capping the steps at 15.Codebruddog/Tecmo_Super_Bowl_NES_DisassemblyrevisedHow we know
1211SET_OFFENSIVE_PLAYER_SKILLS: ; SET OFFENSIVE PLAYER SKILLS ($40 = PLAYER POINTER) ⋮ 1215 LDY #MAX_SPEED_INDEX ; SET SKILL INDEX = MAX SPEED INDEX 1216 JSR GET_PLAYER_SKILL ; GET PLAYER SKILL ( Y= SKILL INDEX) 1217 LDA OFF_MAX_SPEED_VALS,Y ; LOAD SPEED VALUE FROM OFFENSIVE MAX SPEED TABLE ⋮ 1220SET_DEFENSIVE_PLAYER_SKILLS: ; SET DEFENSIVE PLAYER SKILLS NORMAL($40 = PLAYER POINTER) 1221 LDY #MAX_SPEED_INDEX ; SET SKILL INDEX = MAX SPEED INDEX 1222 JSR GET_PLAYER_SKILL ; GET PLAYER SKILL ( Y= SKILL INDEX) 1223 LDA DEF_MAX_SPEED_VALS,Y ; LOAD SPEED VALUE FROM DEFENSIVE MAX SPEED TABLE ⋮ 1225SET_PLAYER_RUNNING_SPEED: ; SET PLAYER SPEED 1226 LDY #MAX_SPEED ; SET CURRENT PLAYER MAX SPEED = MAX SPEED VALUE ⋮ 1229 JSR GET_PLAYER_SKILL ; GET PLAYER SKILL ( Y= SKILL INDEX) ⋮ 1233 JSR GET_PLAYER_SKILL ; GET PLAYER SKILL ( Y= SKILL INDEX) ⋮
Bank27_misc.asm lines 1211–1238 at f3bae0e · upstream ↗ 1146@p1_on_defense: ; P1 ON DEFENSE ⋮ 1149 LDA TEAM_CONTROL_TYPES ; IS P1 PLAYER TYPE = MAN 1150 AND #$F0 ; 1151 BEQ @set_p1_defensive_skills ; YES->SET NORMAL DEFENSE SKILLS ⋮ 1153 LDA TEAM_CONTROL_TYPES ; IS P2 PLAYER TYPE = COA,COM, SKP 1154 AND #$0F ; 1155 BNE @set_p1_defensive_skills ; YES->SET NORMAL DEFENSE SKILLS ⋮ 1158 JSR SET_DEFENSIVE_SKILLS_WITH_COM_BOOST ; SET BOOSTED COM DEFENSIVE RS,RP,MS AND NORMAL HP($40 = PLAYER POINTER)
Bank27_misc.asm lines 1146–1158 at f3bae0e · upstream ↗ 1241SET_DEFENSIVE_SKILLS_WITH_COM_BOOST: ; SET BOOSTED COM DEFENSIVE RS,RP,MS AND NORMAL HP($40 = PLAYER POINTER) ⋮ 1244 LDA DEF_MAX_SPEED_VALS,Y ; LOAD SPEED VALUE FROM DEFENSIVE MAX SPEED TABLE 1245 CLC ; 1246 ADC CPU_DEF_MS_BOOST ; + DEFENSIVE COM MAXIMUM SPEED BOOST ⋮ 1251 JSR ADD_COM_DEF_MS_BOOST ; ADD COM DEFENSIVE RS,RP,MS BOOST INDEX, SET TO MAX VALUE IF TO LARGE(A= MAX SPEED INDEX) ⋮ 1256 JSR ADD_COM_DEF_MS_BOOST ; ADD COM DEFENSIVE RS,RP,MS BOOST INDEX, SET TO MAX VALUE IF TO LARGE(A= MAX SPEED INDEX)
Bank27_misc.asm lines 1241–1261 at f3bae0e · upstream ↗ 1308ADD_COM_DEF_MS_BOOST: ; ADD COM DEFENSIVE SPEED BOOST INDEX, SET TO MAX VALUE IF TO LARGE(A= MAX SPEED INDEX) 1309 CLC ; = MAX SPEED INDEX 1310 ADC CPU_DEF_MS_BOOST ; + COM DEFENSIVE SPEED BOOST INDEX 1311 CMP #MAX_SKILL + 1 ; IS INDEX < MAX INDEX? ⋮ 1314 LDA #MAX_SKILL ; SET MAXIMUM SPEED SKILL INDEX = MAX INDEX
Bank27_misc.asm lines 1308–1314 at f3bae0e · upstream ↗ 5427OFF_MAX_SPEED_VALS: ; OFFENSIVE_MAX_SPEED_VALUES 5428 .DB $15, $16, $17, $18, $19, $1A, $1B, $1C 5429 .DB $1D, $1E, $1F, $20, $21, $22, $23, $24 ⋮ 5431DEF_MAX_SPEED_VALS: ; DEFENSIVE_MAX_SPEED_VALUES 5432 .DB $25, $26, $27, $28, $29, $2A, $2B, $2C 5433 .DB $2D, $2E, $2F, $30, $31, $32, $33, $34
Bank31_fixed_bank.asm lines 5427–5433 at f3bae0e · upstream ↗ 423RESET_CURRENT_SPEED_RP_TO_INITIAL_VALUES: ; INITIALIZE PLAYER RUSHING POWER AND CURRENT SPEED TO DEFAULT VALUES ⋮ 428 LDA RUSHING_POWER_VALUES_TABLE,Y ; SET PLAYER RUSHING POWER COUNTER FROM RUSHING POWER TABLE ADDR + SKILL INDEX OFFSET ⋮ 433 LDA RUNNING_SPEED_VALUES_TABLE,Y ; SET PLAYER RUSHING CURRENT SPEED = STARTING SPEED TABLE ADDR + SKILL INDEX OFFSET
Bank21_22_play_commands_on_field_logic.asm lines 423–434 at f3bae0e · upstream ↗ 440UPDATE_RP_CNT_AND_CUR_SPEED_THEN_COLL_CHECK: ; CHECK FOR PLAYER MOVING AND UPDATE SPEED. IF MOVING RP= RP - 1 441 RETURN_PLAYER_ACTIONS_IN_1_FRAME ⋮ 452 BNE COLL_CHECK_START ; RUSHING POWER COUNTER > 0 YES->COLLISION CHECK START. ⋮ 459 LDA RUSHING_POWER_VALUES_TABLE,X ; SET PLAYER RUSHING POWER COUNTER = FROM RUSHING POWER TABLE ADDR + SKILL INDEX OFFSET ⋮ 467 CMP (CURRENT_PLAYER_ADDR),Y ; PLAYER CURRENT SPEED >= MAX SPEED? 468 BCS COLL_CHECK_START ; YES->COLLISION CHECK START ⋮ 471 CLC ; NO->PLAYER CURRENT SPEED++ 472 ADC #$01 ;
Bank21_22_play_commands_on_field_logic.asm lines 440–475 at f3bae0e · upstream ↗ 11366RUSHING_POWER_VALUES_TABLE: ;RUSHING_POWER_VALUES 11367 .DB $0D,$0C,$0B,$0A,$09,$08,$07,$06,$05,$04,$03,$03,$02,$02,$01,$01 ⋮ 11369RUNNING_SPEED_VALUES_TABLE: ;RUNNING_SPEED_VALUES 11370 .DB $0E,$0F,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1A,$1B,$1C,$1D
Bank21_22_play_commands_on_field_logic.asm lines 11366–11370 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^Each side picks one of eight slots. The offense's slot reads a play id (0 to 63) from its playbook, and before the snap the game reads the defense's play from a 64-row table: the row is the offense's play id, and the column is the defense's slot. In all 64 rows, the entry in column id ÷ 8, the play's group, is a defensive play that appears nowhere else in the table, one of 11 such plays (computed from the table by the atlas). The playbook-change screen offers slot k only the plays of group k (ids k × 8 to k × 8 + 7), so for a playbook set there, that column is the slot the offense called.Codebruddog/Tecmo_Super_Bowl_NES_Disassemblyrevised
How we know
3061P1_ON_OFF_LOAD_PLAY_INFO_PLAYER_RAM: ; P1 ON OFFENSE LOAD PLAY INFORMATION INTO PLAYER RAM(A=PLAY SELECTED 3062 LDX P1_PLAY_CALL ; LOAD P1 SLOT CALLED 3063 LDA P1_PLAYBOOK_EDIT,X ; GET ACTUAL PLAY CALLED USING SLOT AS INDEX TO P1 PLAYBOOK IN SRAM ⋮ 3089 TAX ; ⋮ 3092@get_def_reaction_based_on_off_play: ⋮ 3095 LDY P1_PLAY_CALL ; LOAD PLAYER 1 PLAY CALL 3096 LDA P1_PLAYBOOK_EDIT,Y ; GET ACTUAL PLAY 3097@multiply_by_eight_add_starting_offset: ⋮ 3105 ADC #<DEF_REACTION_START_ADDR ; = OFFSET PLUS DEFENSIVE REACTION LIST STARTING ADDR 0X1DC10= $BC00 ⋮ 3112 LDY P2_PLAY_CALL ; SAVE DEFENSIVE PLAY INDEX IN X 3113 LDA (def_reaction_addr),Y ; 3114 TAX ; ⋮
Bank19_20_on_field_gameplay_loop.asm lines 3061–3115 at f3bae0e · upstream ↗ 2979DRAW_SUB_PLAYS_IN_SCROLLING_WINDOW: ; DRAW SUBSTITUTE PLAYS (A= PLAY SLOT) 2980 ASL ; SHIFT BY 8 SINCE 8 PLAYS PER SLOT 2981 ASL ; 2982 ASL ; 2983 AND #$38 ; MAKE SURE ADJUSTED PLAY SLOT IS 0 THROUGH 7
Bank17_18_main_game_loop.asm lines 2979–2983 at f3bae0e · upstream ↗ 2885 LDA current_play_index_in_slot ; MAKE SURE PLAY INDEX IS BETWEEN 0 -7 2886 AND #$07 ; 2887 STA current_play_index_in_slot ; 2888 CLC ; 2889 ADC MENU_X ; + PLAY SLOT OFFSET 2890 STA current_play_id ; = PLAY ID
Bank17_18_main_game_loop.asm lines 2885–2890 at f3bae0e · upstream ↗ 2812DEFENSIVE_PLAY_INDEX_TABLE: ; DEFENSE REACTION INDEX TO SET OF PLAYER POINTERS 2813 .DB $5B,$5A,$5A,$58,$58,$59,$59,$59 ; REACTION TO T- FAKE SWEEP ⋮ 2876 .DB $2A,$2A,$29,$29,$2B,$2B,$2B,$22 ; REACTIONS TO RED-GUN SLANT
Bank15_faces_playbooks.asm lines 2812–2876 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^Reactions 128 and 177 are player scripts used only by the 11 guess-only defensive plays (computed by the atlas over bank 4). Reaction 128 waits for the snap, sets the player's running-speed rating to 15, adds 48 to his max speed and 48 to his hitting power, moves, and then loops a
runRushcommand; reaction 177 stands for 30 frames after the snap and then jumps into reaction 128's boosts. Execution 188, one of the 11, gives reactions 128 to 134 to its first seven players. The script command the disassembly's macro callsboostRSemits$E3, which the command table maps to the routine that adds to max speed.Codebruddog/Tecmo_Super_Bowl_NES_DisassemblyrevisedHow we know
4811DEFENSE_PLAYER_REACTION_128: ⋮ 4814DEFENSE_PLAYER_REACTION_JUMP_059:
Bank5_6_off_def_play_data.asm lines 4811–4819 at f3bae0e · upstream ↗ 5200DEFENSE_PLAYER_REACTION_177:Bank5_6_off_def_play_data.asm lines 5200–5204 at f3bae0e · upstream ↗ 5281DEFENSE_PLAYER_REACTION_191:Bank5_6_off_def_play_data.asm lines 5281–5284 at f3bae0e · upstream ↗ 258.MACRO PlayerCommandData.setRS value 259 .DB $E0 ⋮ 273.MACRO PlayerCommandData.boostRS boost 274 .DB $E3
macros/play_data_macros.asm lines 258–276 at f3bae0e · upstream ↗ 350.MACRO PlayerCommandData.boostHP boost 351 .DB $F7
macros/play_data_macros.asm lines 350–352 at f3bae0e · upstream ↗ 383 .WORD SET_RS_COMMAND_START-1 ; EO SET RS ⋮ 386 .WORD INCR_DECR_MS_COMMAND_START-1 ; E3 BOOST MS ⋮ 409 .WORD CHANGE_HITTING_POWER_COMMAND_START-1 ; F7 BOOST HP
Bank21_22_play_commands_on_field_logic.asm lines 383–409 at f3bae0e · upstream ↗ 329.MACRO PlayerCommandData.stand time 330 .DB $F3
macros/play_data_macros.asm lines 329–330 at f3bae0e · upstream ↗ 4321stand_frames = PLAYER_COMMAND_ARG1 ⋮ 4323STAND_COMMAND_START: ; F3 STAND (TIME) ⋮ 4325 LDA stand_frames ; LOAD # OF FRAMES TO WAIT
Bank21_22_play_commands_on_field_logic.asm lines 4321–4329 at f3bae0e · upstream ↗ 3131SET_RS_COMMAND_START: ; E0 SET RS 3132 LOAD_CUR_PLAYER_RP_RS_INDEXES 3133 AND #$F0 ; MASK OUT RS SKILL INDEX NIBBLE 3134 ORA new_rs_value ; = OLD RP INDEX + NEW RS INDEX
Bank21_22_play_commands_on_field_logic.asm lines 3131–3135 at f3bae0e · upstream ↗ 3212INCR_DECR_MS_COMMAND_START: ; E3 CHANGE MS (AMOUNT) 3213 LOAD_CUR_PLAYER_MAX_SPEED 3214 CLC ; 3215 ADC change_max_speed_value ; + AMOUNT TO BOOST MAX SPEED 3216 STA (CURRENT_PLAYER_ADDR),Y ; SAVE PLAYER MAX SPEED
Bank21_22_play_commands_on_field_logic.asm lines 3212–3216 at f3bae0e · upstream ↗ 4421CHANGE_HITTING_POWER_COMMAND_START: ; F7 BOOST HP 4422 LDA hp_change_value ; = AMOUNT TO BOOST HP + CURRENT HP 4423 LDY #HP_INDEX ; 4424 CLC ; 4425 ADC (CURRENT_PLAYER_ADDR),Y ;
Bank21_22_play_commands_on_field_logic.asm lines 4421–4428 at f3bae0e · upstream ↗ 3233LOAD_DEFENSIVE_CODE_ADDRESSES: ; LOAD DEFENSIVE PLAYER POINTERS STARTING ADDRESS 3234 LDA #SIZE_OF_ALL_PLAY_POINTERS ; LOAD 11 PLAYERS * 2 BYTES PER PLAYER = 22 PLAY POINTER BYTES/ PLAY 3235 JSR MULTIPLY_A_TIMES_X ; 3236 ; PLAY POINTER OFFSET + DEFENSIVE PLAY POINTER STARTING ADDRESS 3237 ADD_16BIT_CONST_TO_ZP[val_addr] $A000, play_ptrs_addr
Bank19_20_on_field_gameplay_loop.asm lines 3233–3237 at f3bae0e · upstream ↗ 2252DEFENSIVE_EXECUTION_188:Bank4_def_spec_play_pointers_data.asm lines 2252–2259 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abA computer-controlled defense picks its slot at random, 0 to 7, except on third and fourth down. There, with under 25 eighths of a yard to the first-down line (3 yards or less), it calls a run slot (0–3) when a sum of random bytes is under 205 (computed: 80%) and a pass slot (4–7) otherwise. As the atlas reads it, the check meant to favor passes on longer yardage compares the distance's high byte with 57 (
$39), and that byte is at most 3 on a 100-yard field, so every longer third or fourth down also gets a random slot.Codebruddog/Tecmo_Super_Bowl_NES_DisassemblyrevisedHow we know
4342DO_COM_DEFENSIVE_PLAY_CALL: ; CHECK FOR COM DEFENSIVE PLAY CALL ⋮ 4345 LDA DOWN ; IS DOWN = 3RD DOWN 4346 CMP #THIRD_DOWN ; 4347 BEQ @check_yards_less_three_third_or_fourth_down ; YES->CHECK FOR YDS TO GO <3 ON 3RD ANF 4TH DOWN 4348 CMP #FOURTH_DOWN ; IS DOWN = 4TH DOWN 4349 BEQ @check_yards_less_three_third_or_fourth_down ; YES->CHECK FOR YDS TO GO <3 ON 3RD ANF 4TH DOWN ⋮ 4354 AND #$07 ; MAKE RAND # 0 THRU 7 = EQUAL CHANCE OF ANY PLAY ⋮ 4359 LDA yards_to_go ; IS YARDS TO FIRST >= 3 4360 CMP #$19 ; 4361 LDA yards_to_go + 1 ; 4362 SBC #$00 ; 4363 BCS @check_yards_to_go_greater_than_7 ; YES-> ⋮
Bank12_13_sim_update_stats.asm lines 4342–4372 at f3bae0e · upstream ↗ 4123HEAVY_RUN_80PCT_COM_PLAY_CALL: ; HEAVILY RANDOMIZED PLAY CALL 80% RUN, 20% PASS ⋮ 4135 CMP #$CD ; RAND # < 0XCD = 80% CHANCE RUN PLAY, 20% PASS 4136 BCC @call_random_com_run_play ; YES->CALL RANDOM RUN PLAY ⋮ 4139 LDA temp_rand_value + 1 ; MAKE PLAY CALL = RANDOM PASS PLAY CALL(4-7) ⋮ 4150 LDA temp_rand_value + 1 ; MAKE PLAY CALL = RANDOM RUN PLAY CALL (0-3)
Bank12_13_sim_update_stats.asm lines 4123–4153 at f3bae0e · upstream ↗ 4285CHECK_IF_COM_TAKES_TIMEOUT_ON_DEFENSE: ; COM ON DEFENSE CHECK IF TIMEOUTS NEEDED ⋮ 4292 BPL DO_COM_DEFENSIVE_PLAY_CALL ; NO->CHECK FOR COM DEFENSIVE PLAY CALL
Bank12_13_sim_update_stats.asm lines 4285–4296 at f3bae0e · upstream ↗ 3468yards_to_go = LOCAL_5Bank12_13_sim_update_stats.asm line 3468 at f3bae0e · upstream ↗ 1864yards_for_first = LOCAL_5 ⋮ 1918 SBC LOS_X ⋮ 1925 ADC #$50 ; ADD 10 yards ⋮ 1931 CMP #<FRONT_RIGHT_ENDZONE ⋮ 1942 SBC LOS_X
Bank20_playcall.asm lines 1864–1946 at f3bae0e · upstream ↗ 30FRONT_RIGHT_ENDZONE = $0990constants_variables/field_locations.asm lines 22–30 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^When two computer-controlled players collide, the game compares their hitting power (HP), loaded from a table at 4 per rating step (0 to 60). If neither leads by 16 (4 steps), they hold for 8 frames plus random waits of up to 255, 255, and 63 frames, and one random bit picks the winner. With a lead of 16 to 31, the stronger player wins when a random byte is under 170 (computed: 66%); otherwise they grapple as before. With a lead of 32 or more, the stronger player wins on a byte under 205 (computed: 80%); otherwise they hold 64 frames and then grapple.Codebruddog/Tecmo_Super_Bowl_NES_Disassembly
How we know
1263SET_PLAYER_HP_AND_SKIN_COLOR: ; SET PLAYER HITTING POWER 1264 LDY #HITTING_POWER_INDEX ; SET SKILL INDEX = HITTING POWER INDEX 1265 JSR GET_PLAYER_SKILL ; GET PLAYER SKILL ( Y= SKILL INDEX) 1266 TAX ; 1267 LDA HITTING_POWER_VALS,X ; LOAD HITTING POWER FROM HITTING POWER TABLE
Bank27_misc.asm lines 1263–1269 at f3bae0e · upstream ↗ 5435HITTING_POWER_VALS: ; HITTING_POWER_VALUES: 5436 .DB $00, $04, $08, $0C, $10, $14, $18, $1C 5437 .DB $20, $24, $28, $2C, $30, $34, $38, $3C
Bank31_fixed_bank.asm lines 5435–5437 at f3bae0e · upstream ↗ 4COM_VS_COM_OFF_HP_THRESH_1 = $10 ; 25 HP 5COM_VS_COM_OFF_HP_THRESH_2 = $20 ; 50 HP ⋮ 7COM_VS_COM_DEF_HP_THRESH_1 = $F0 ; 25 HP 8COM_VS_COM_DEF_HP_THRESH_2 = $E0 ; 50 HP
Bank21_22_play_commands_on_field_logic.asm lines 4–8 at f3bae0e · upstream ↗ 55MEDIUM_COM_COM_OL_THROW_CHANCE = $AA ; 33% dont throw 56HIGH_COM_COM_OL_THROW_CHANCE = $CD ; 20% dont throw ⋮ 60MEDIUM_COM_COM_DEF_THROW_CHANCE = $AA ; 66% chance player busts in vs continue grapple 61HIGH_COM_COM_DEF_THROW_CHANCE = $CD ; 20% dont throw
Bank21_22_play_commands_on_field_logic.asm lines 55–61 at f3bae0e · upstream ↗ 777COM_V_COM_COLLIDED_START: ; COM VS COM GRAPPLE START 778 LOAD_CUR_PLAYER_HITTING_POWER ; PLAYER HP- TARGET HP 779 SEC ; 780 SBC (defense_addr),Y ; 781 BCC COM_DEF_HP_MORE_THAN_OFF ; DEFENSE HP > OFFENSE HP? YES-> DEFENSE HP > OFFENSE ⋮ 787 CMP #COM_VS_COM_OFF_HP_THRESH_1 ; OFFENSE HP > DEFENSE HP BY >= 4 NOTCHES (25HP)? 788 BCC COM_VS_COM_LONG_GRAPPLE_START ; NO-> COM V COM NORMAL GRAPPLE ⋮ 791 CMP #COM_VS_COM_OFF_HP_THRESH_2 ; OFFENSE HP > DEFENSE HP BY >=8 NOTCHES (50HP)? ⋮ 801 CMP #COM_VS_COM_DEF_HP_THRESH_1 +1 ; DEFENSE HP < 4 NOTCHES GREATER? 802 BCS COM_VS_COM_LONG_GRAPPLE_START ; YES->COM V COM NORMAL GRAPPLE ⋮ 805 CMP #COM_VS_COM_DEF_HP_THRESH_2 +1 ; DEFENSE HP >= 8 NOTCHES MORE THAN OFFENSE HP
Bank21_22_play_commands_on_field_logic.asm lines 777–810 at f3bae0e · upstream ↗ 817COM_VS_COM_SET_RANDOM_GRAPPLE_TIME: ; NORMAL GRAPPLE TIME DELAY START 818 RETURN_PLAYER_ACTIONS_IN_NUM_FRAMES[frames] 8 819 JSR UPDATE_RANDOM_1 ; UPDATE RANDOM $3B AND LOAD VALUE() = SET FRAMES TO WAIT = RANDOM 0-0xFF FRAMES (0-4.2 sec) ⋮ 824 AND #$3F ; ⋮ 826 JSR UPDATE_RANDOM_1 ; UPDATE RANDOM $3B AND LOAD VALUE() 827 BMI DEFENSE_WINS_COM_COM_GRAPPLE ; 50%->COM V COM DEFENDER WINS, BUSTS IN WITH OFFENSE RANDOMLY THROWN ON GROUND
Bank21_22_play_commands_on_field_logic.asm lines 817–827 at f3bae0e · upstream ↗ 862MEDIUM_CHANCE_DEF_COM_THROWN: ; OFFENSE HP > DEFENSE BY > 4 NOTCHES <8 ⋮ 867 JSR UPDATE_RANDOM_3 ; UPDATE RANDOM $3D AND LOAD VALUE() 868 CMP #MEDIUM_COM_COM_OL_THROW_CHANCE ; 869 BCC @defender_thrown ; 60% -> COM DEFENDER THROWN, OFFENSIVE PLAYER FLATTENED OR STAYS STANDING 870 JMP COM_VS_COM_SET_RANDOM_GRAPPLE_TIME ; 40% -> COM V COM NORMAL GRAPPLE
Bank21_22_play_commands_on_field_logic.asm lines 862–870 at f3bae0e · upstream ↗ 895HIGH_CHANCE_DEF_COM_THROWN: ; OFFENSE HP > DEFENSE BY 8 NOTCHES ⋮ 901 CMP #HIGH_COM_COM_OL_THROW_CHANCE ; 902 BCS DELAY_THEN_NORMAL_GRAPPLE ; 25% ->64(1 SEC) FRAME DELAY THEN JUMP TO NORMAL GRAPPLE ⋮ 922DELAY_THEN_NORMAL_GRAPPLE: ; 64 (~1 SEC) FRAME DELAY THEN JUMP TO COM V COM GRAPPLE 923 RETURN_PLAYER_ACTIONS_IN_NUM_FRAMES[frames] 64 924 JMP COM_VS_COM_SET_RANDOM_GRAPPLE_TIME ; JUMP -> COM V COM NORMAL GRAPPLE
Bank21_22_play_commands_on_field_logic.asm lines 895–924 at f3bae0e · upstream ↗ 926MEDIUM_CHANCE_OFF_COM_THROWN: ; DEFENSE HP > OFFFENSE BY > 4 NOTCHES <8 ⋮ 932 CMP #MEDIUM_COM_COM_DEF_THROW_CHANCE ; 933 BCC @offense_thrown ; 66%-> DEFENDER WINS GRAPPLE OFFENSIVE PLAYER THROWN ⋮ 958HIGH_CHANCE_OFF_COM_THROWN: ; OFFENSIVE PLAYER THROWN DEFENSE HP > OFFFENSE BY > 8 NOTHCES ⋮ 964 CMP #HIGH_COM_COM_DEF_THROW_CHANCE ; 965 BCS DELAY_THEN_NORMAL_GRAPPLE ; 20% ->(~1 SEC) FRAME DELAY THEN JUMP TO COM V COM GRAPPLE
Bank21_22_play_commands_on_field_logic.asm lines 926–965 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abAn ordinary collision (not a dive or a chop block) between a human-controlled and a computer-controlled player goes to
MAN_VS_COM_POPCORN_CHECK. If the human player's HP is at least 32 higher (8 rating steps), the computer player is thrown at once; otherwise both hold for 64 frames while the game counts the human's A presses, and 2 or more throw the computer player, and fewer throw the human. Between two human players, both players' presses count over the same 64 frames. The defender wins with at least as many presses as the offensive player; if neither pressed, both go down.Codebruddog/Tecmo_Super_Bowl_NES_DisassemblyrevisedHow we know
530@offense_colliding_defender: ; ; /OFFENSIVE PLAYER COLLIDING WITH DEFENDER START/ 531 LOAD_CUR_PLAYER_MOVEMENT_STATUS ; IS PLAYER DIVING FOR TACKLE/ CHOP BLOCKING? 532 AND #(PLAYER_DIVE_TACKLE_BITFLAG+PLAYER_CHOP_BLOCK_BITFLAG) ⋮ 535 JMP OFFENSE_DIVING_FOR_TACKLE ; YES->OFFENSE PLAYER DIVING FOR TACKLE COLLISION ⋮ 540 JMP OFFENSIVE_CHOP_BLOCK_COLLISION ; YES-> OFFENSIVE PLAYER CHOP BLOCK ⋮ 548@check_defender_diving_chop_block: ; CHECK FOR DEFENDER DIVING OR CHOPPING 549 LDA (defender_addr),Y ; DOES DEFENDER MOVEMENT = DIVING FOR TACKLE OR CHOP BLOCKING? 550 AND #(PLAYER_DIVE_TACKLE_BITFLAG+PLAYER_CHOP_BLOCK_BITFLAG) 551 BEQ START_OF_NORMAL_COLLISION_OFF_DEF ; NO-> NORMAL PLAYER COLLISION
Bank21_22_play_commands_on_field_logic.asm lines 530–551 at f3bae0e · upstream ↗ 570START_OF_NORMAL_COLLISION_OFF_DEF: ; NORMAL OFF AND DEF PLAYER COLLISION ⋮ 574 LDY #<(CHECK_COL_TYPE_MAN_OR_COM-1) ; SET COLLISION ADDR = CHECK COLLISION TYPE (MAN,COM)
Bank21_22_play_commands_on_field_logic.asm lines 570–576 at f3bae0e · upstream ↗ 749CHECK_COL_TYPE_MAN_OR_COM: ; CHECK COLLISION TYPE (MAN,COM) ⋮ 752 AND #PLAYER_MAN_COM_BITFLAG ; 753 BEQ @com_vs_com_check ; NO->CHECK FOR MAN DEFENDER ⋮ 757 AND #PLAYER_MAN_COM_BITFLAG ; 758 BEQ @man_vs_com_jump_popcorn_check ; NO->MAN VS COM POPCORN CHECK JUMP ⋮ 761 JMP MAN_VS_MAN_GRAPPLE_START ; YES->MAN V MAN GRAPPLE START ⋮ 764 JMP MAN_VS_COM_POPCORN_CHECK ; JUMP->MAN VS COM POPCORN CHECK ⋮ 766@com_vs_com_check: ; CHECK FOR MAN DEFENDER GRAPPLE ⋮ 768 AND #PLAYER_MAN_COM_BITFLAG ; ⋮ 770 JMP PAUSE_COLL_CHECK_RECHECK_COLL_TYPE ; *** should never reach here
Bank21_22_play_commands_on_field_logic.asm lines 749–770 at f3bae0e · upstream ↗ 987PAUSE_COLL_CHECK_RECHECK_COLL_TYPE: ; *** should never reach here 988 LDY #<(CHECK_COL_TYPE_MAN_OR_COM-1) ; SET COMMAND ADDR = CHECK COLLISION TYPE (MAN,COM) 989 LDX #>(CHECK_COL_TYPE_MAN_OR_COM-1) ; 990 JSR UPDATE_LOCAL_PLAYER_COMMAND_ADDR_IF_VALID ; LOAD COMMAND ADDRESS AND UPDATE COMMAND COUNTER ( TARGET: $3E $3F)
Bank21_22_play_commands_on_field_logic.asm lines 987–991 at f3bae0e · upstream ↗ 10MAN_VS_COM_POPCORN_THRESHOLD = $20 ; 50 HP differentialBank21_22_play_commands_on_field_logic.asm line 10 at f3bae0e · upstream ↗ 1001MAN_VS_COM_POPCORN_CHECK: ; MAN VS COM POPCORN CHECK ⋮ 1003 LDY #HP_INDEX ; MAN HP - COM HP 1004 LDA (CURRENT_PLAYER_ADDR),Y ; 1005 SEC ; 1006 SBC (com_addr ),Y ; 1007 BCC @man_vs_com_grapple_check ; COM HP >MAN? YES->MAN VS COM GRAPPLE CHECK 1008 CMP #MAN_VS_COM_POPCORN_THRESHOLD ; MAN HP 50 HP MORE THAN COM? 1009 BCS @com_popcorned_or_outapped ; YES->COM THROWN ⋮ 1015 RETURN_PLAYER_ACTIONS_IN_NUM_FRAMES[frames] 64 1016 LDY #players_taps ; LOAD MAN PRESSES 1017 LDA (CURRENT_PLAYER_ADDR),Y ; 1018 CMP #com_total_taps ; MAN PRESSES > (COM PRESSES = 2) ⋮
Bank21_22_play_commands_on_field_logic.asm lines 1001–1019 at f3bae0e · upstream ↗ 998players_taps = EXTRA_PLAYER_RAM_3 999com_total_taps = $02
Bank21_22_play_commands_on_field_logic.asm lines 998–999 at f3bae0e · upstream ↗ 606COUNT_PRESSES_GRAPPLE_IF_MAN: ; SET GRAPPLES PRESSES TO ZERO, CHECK FOR MAN OR COM 607 RETURN_PLAYER_ACTIONS_IN_1_FRAME 608 LDA #$00 ; SET COLLISION PRESSES = ZERO 609 LDY #presses ; ⋮ 615@count_man_a_presses: ; GRAPPLE COLLISION MAN BUTTON PRESS LOOP 616 RETURN_PLAYER_ACTIONS_IN_1_FRAME 617 JSR GET_PLAYER_JOY_PRESS ; GET P1 OR P2 JOYPAD PRESS() ⋮ 619 LDY #presses ; PRESSES++ ⋮ 624 JMP @count_man_a_presses ; JUMP->GRAPPLE COLLISION MAN BUTTON PRESS LOOP
Bank21_22_play_commands_on_field_logic.asm lines 606–624 at f3bae0e · upstream ↗ 1043MAN_VS_MAN_GRAPPLE_START: ; MAN V MAN GRAPPLE START ⋮ 1047 RETURN_PLAYER_ACTIONS_IN_NUM_FRAMES[frames] 64 ⋮ 1049 LDY #players_taps ; DEFENSE PRESSES >= OFFENSE PRESSES 1050 LDA (defender_addr),Y ; 1051 CMP (CURRENT_PLAYER_ADDR),Y ; 1052 BCS @defense_wins_man_man_grapple ; YES->DEFENSE WINS GRAPPLE ⋮ 1060@defense_wins_man_man_grapple: ; DEFENSE WINS MAN GRAPPLE 1061 TAX ; DID DEFENSE TIE OFFENSE? 1062 BEQ @defense_wins_man_man_grapple_equal_presses ; YES->DEFENSE WINS GRAPPLE EQUAL PRESSES ⋮ 1069@defense_wins_man_man_grapple_equal_presses: ; DEFENSE TIES MAN GRAPPLE EQUAL PRESSES 1070 LDY #<(PLAYER_ON_GRND_CHECK_TACKLE_IF_BALL_CARRIER-1) ; SET DEFENDER COMMAND ADDR = PLAYER FLATTENED,IF PLAYER BALL CARRIER CHECK FOR TACKLE ⋮ 1074 JMP PLAYER_ON_GRND_CHECK_TACKLE_IF_BALL_CARRIER ; JUMP->PLAYER FLATTENED,IF PLAYER BALL CARRIER CHECK FOR TACKLE
Bank21_22_play_commands_on_field_logic.asm lines 1043–1074 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^When a pass reaches its target, Tecmo Super Bowl adds the passer's pass control (PC) value, 61 to 91 at 2 per step, to the receiver's reception (REC) value, also 61 to 91. With no defender near the ball, a random byte forced into 128–255, times that sum and divided by 256, gives a roll from half the sum to one less than it; 79 or more is a catch, and less is incomplete. Each of up to three nearby defenders in turn subtracts his interception (INT) value, 51 to 81, from the sum (floored at 0) for a roll made the same way: under 51 is an interception, under 80 is incomplete, and 80 or more passes the ball to the next defender's check. A pass that clears every check is a catch.Codebruddog/Tecmo_Super_Bowl_NES_Disassembly
How we know
184COVERED_INTERCEPTION_THRESHOLD = $33 185UNCOVERED_RECEPTION_THRESHOLD = $4F 186COVERED_RECEPTION_THRESHOLD = $50 187TARGET_NOT_CLOSE_INT_THRESHOLD = $0E
Bank21_22_play_commands_on_field_logic.asm lines 184–187 at f3bae0e · upstream ↗ 5675ADD_PASS_CONTROL_SKILL_AND_REC_SKILL: ; GET PC TABLE VALUE, REC TABLE VALUE, PC VAL in $DC, PC+REC VAL in $DD() ⋮ 5679 JSR GET_PASS_CONTROL_SKILL_VALUE ; GET PLAYER PASSING CONTROL INDEX() 5680 TAY ; SET PASSING ABILITY TABLE INDEX 5681 LDA PASSING_VALUES_TABLE,Y ; LOAD PASS CONTROL ABILITY VALUE FROM PASSING ABILITY TABLE 5682 STA PASS_CONTROL_VALUE ; ⋮ 5685 LDY #RECEPTION_INDEX ; SET SKILL INDEX = RECEPTTION ⋮ 5687 TAY ; ⋮ 5692 CLC ; ⋮ 5694 TAY ; ⋮ 5700 LDA RECEPTION_VALUES_TABLE,Y ; LOAD RECEIVING ABILITY VALUE FROM PASSING ABILITY TABLE 5701 CLC ; 5702 ADC PASS_CONTROL_VALUE ; + PASS CONTROL VALUE ⋮
Bank21_22_play_commands_on_field_logic.asm lines 5675–5703 at f3bae0e · upstream ↗ 5972GET_PASS_CONTROL_SKILL_VALUE: ; GET PLAYER PASSING CONTROL SKILL VALUE() 5973 LDY #PASS_CONTROL_INDEX ; LOAD PASS CONTROL SKILL INDEX 5974 JSR GET_PLAYER_SKILL_OR_FACE ; GET SKILL RATING(A=PLAYER, Y=SKILL TO GET, X=TEAM)
Bank21_22_play_commands_on_field_logic.asm lines 5972–5974 at f3bae0e · upstream ↗ 11465PASSING_VALUES_TABLE: ; PASSING_VALUES 11466 .DB $3D,$3F,$41,$43,$45,$47,$49,$4B,$4D,$4F,$51,$53,$55,$57,$59,$5B ⋮ 11468RECEPTION_VALUES_TABLE: ; RECEPTION_VALUES 11469 .DB $3D,$3F,$41,$43,$45,$47,$49,$4B,$4D,$4F,$51,$53,$55,$57,$59,$5B ⋮ 11471INTERCEPTION_VALUES_TABLE: ; INTERCEPTION_VALUES 11472 .DB $33,$35,$37,$39,$3B,$3D,$3F,$41,$43,$45,$47,$49,$4B,$4D,$4F,$51
Bank21_22_play_commands_on_field_logic.asm lines 11465–11472 at f3bae0e · upstream ↗ 5481PASS_RESULT_CALCS_NO_DEFENDER_NEAR: ⋮ 5486 LDA RANDOM_3 ; MAKE RAND # 3D RANGE = 0X80 TO 0XFF 5487 ORA #$80 ; 5488 LDX PC_PLUS_RECEPTION ; LOAD PC+REC 5489 JSR MULTIPLY_A_TIMES_X ; MULTIPLY (A * X) (X-1 to X/2 Stored in $45) 5490 LDA qb_to_wr_check_value ; RANGE = PC+REC-1 to (PC+REC-1)/2 5491 CMP #UNCOVERED_RECEPTION_THRESHOLD ; VALUE > RECEPTION THRESHOLD 5492 BCS RECEPTION_NORMAL ; YES->RECEPTION
Bank21_22_play_commands_on_field_logic.asm lines 5481–5492 at f3bae0e · upstream ↗ 5502PASS_RESULT_CALCS_DEFENDER_NEAR: ⋮ 5505 LDX PC_PLUS_RECEPTION ; LOAD X WITH PC+REC TABLE VALS 5506 LDA PLAYERS_CAN_COLLIDE_BALL_PASS ; LOAD 1st PRIORITY DEFENDER 5507 JSR PC_REC_INT_ADJUST_BY_RAND_FOR_PASS_OUTCOME ; PC,REC,INT CALCULATION ROUTINE (A=DEFENDER VALUE, X=PC OR PC+REC) 5508 BCC @check_2nd_def_wr_near ; 1ST DEFENDER CANT DEFEND->2ND DEFENDER WITH WR CHECK ⋮ 5512 CMP #COVERED_INTERCEPTION_THRESHOLD ; VALUE < INTERCEPTION THRESHOLD 5513 BCC INTERCEPTION_NORMAL ; YES-> BALL INTERCEPTED ⋮ 5516 CMP #COVERED_RECEPTION_THRESHOLD ; VALUE > RECEPTION THRESHOLD 5517 BCC BALL_TIPPED_OR_INCOMPLETE ; NO->BALL INCOMPLETE ⋮ 5520 LDX PC_PLUS_RECEPTION ; LOAD X WITH PC+REC TABLE VALS ⋮ 5522 JSR PC_REC_INT_ADJUST_BY_RAND_FOR_PASS_OUTCOME ; PC,REC,INT CALCULATION ROUTINE (A=DEFENDER VALUE, X=PC OR PC+REC ⋮ 5527 CMP #COVERED_INTERCEPTION_THRESHOLD ; VALUE < INTERCEPTION THRESHOLD ⋮
Bank21_22_play_commands_on_field_logic.asm lines 5502–5547 at f3bae0e · upstream ↗ 5713PC_REC_INT_ADJUST_BY_RAND_FOR_PASS_OUTCOME: ; PC,REC,INT CALCULATION ROUTINE (A=DEFENDER VALUE, X=PC OR PC+REC) ⋮ 5722 LDY #INTERCEPTION_INDEX ; SET SKILL INDEX = INTERCEPTTION ⋮ 5742 LDA pc_rec_value ; LOAD PC+REC OR JUST PC 5743 SEC ; 5744 SBC INTERCEPTION_VALUES_TABLE,Y ; - INT VALUE VALUE FROM INT ABILITY TABLE 5745 BCS @get_final_calculation_value ; 5746 LDA #$00 ; MAKES ALWAYS AN INT ⋮ 5751 JSR HEAVIER_RANDOMIZE ; MORE RANDOM RANDOM # SAVE INTO A REGISTER() 5752 ORA #$80 ; MAKE RAND # RANGE (80-FF) 5753 JSR MULTIPLY_A_TIMES_X ; MULTIPLY (A * X) 5754 LDA pc_rec_int_result ; RANGE= X-1 to X/2 X = (PC+REC-INT)
Bank21_22_play_commands_on_field_logic.asm lines 5713–5754 at f3bae0e · upstream ↗ 4054a_register = LOCAL_8 ⋮ 4058MULTIPLY_A_TIMES_X: ; 8 BIT MULTIPLY (A times X) RESULT IN $44,45
Bank31_fixed_bank.asm lines 4054–4077 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^When the target isn't close enough to the ball, nearby defenders can still intercept: each in turn subtracts his INT value from the variable the code names
PASS_CONTROL_VALUEand rolls as for a covered pass, intercepting under 14; otherwise the pass is incomplete. This path doesn't callADD_PASS_CONTROL_SKILL_AND_REC_SKILL, the routine that stores the passer's value in that variable (the close-target and the jump-or-dive paths call it), so it uses whatever player-command argument was last stored there. The disassembly marks it "***MAJOR BUG!!".Codebruddog/Tecmo_Super_Bowl_NES_DisassemblyrevisedHow we know
5675ADD_PASS_CONTROL_SKILL_AND_REC_SKILL: ; GET PC TABLE VALUE, REC TABLE VALUE, PC VAL in $DC, PC+REC VAL in $DD() ⋮ 5682 STA PASS_CONTROL_VALUE ;
Bank21_22_play_commands_on_field_logic.asm lines 5675–5682 at f3bae0e · upstream ↗ 5451PASS_CONTROL_VALUE = PLAYER_COMMAND_ARG1 ; *** could maybe use local ⋮ 5458 JSR CHECK_PLAYER_CLOSE_ENOUGH_TO_BALL ; IS PLAYER CLOSE ENOUGH TO BALL() 5459 BCC PASS_CALCULATION_TARGET_NOT_CLOSE_TO_BALL ; NO->CHECK IF DEFENDERS CAN INTERCEPT TARGET NOT CLOSE ENOUGH() ⋮ 5466TARGET_JUMP_DIVE_PASS_CALC_START: ; PASS TARGET JUMP/DIVE CALCULATIONS() IF PASS RESULT ALREADY RET AND SEC & ClV ⋮ 5469CHECK_ANY_DEFENDER_CAN_AFFECT_PASS: ; CHECK IF ANY DEFENDER CAN IMPACT PASS 5470 JSR ADD_PASS_CONTROL_SKILL_AND_REC_SKILL ; GET PC TABLE VALUE, REC TABLE VALUE, PC VAL in $DC, PC+REC VAL in $DD()
Bank21_22_play_commands_on_field_logic.asm lines 5451–5470 at f3bae0e · upstream ↗ 5552 ; ***MAJOR BUG!! $DC NOT LOADED WITH PASS CONTROL VALUE 5553 ; WILL BE WHATEVER COMMAND ARGUMENT BYTE WAS IN THERE LAST 5554PASS_CALCULATION_TARGET_NOT_CLOSE_TO_BALL: ; CHECK IF DEFENDERS CAN INTERCEPT TARGET NOT CLOSE ENOUGH() ⋮ 5563 LDX PASS_CONTROL_VALUE ; LOAD X WITH PC VALUE *** BUG 5564 LDA PLAYERS_CAN_COLLIDE_BALL_PASS ; LOAD 1ST PRIORITY DEFENDER STATUS + ID 5565 JSR PC_REC_INT_ADJUST_BY_RAND_FOR_PASS_OUTCOME ; PC,REC,INT CALCULATION ROUTINE (A=DEFENDER VALUE, X=PC OR PC+REC) ⋮ 5568 CMP #TARGET_NOT_CLOSE_INT_THRESHOLD ; VALUE < NO WR INTERCEPTION THRESHOLD 5569 BCC INTERCEPTION_NORMAL ; YES->INTERCEPTION ⋮ 5572 LDX PASS_CONTROL_VALUE ; LOAD X WITH PC VALUE *** BUG ⋮ 5574 JSR PC_REC_INT_ADJUST_BY_RAND_FOR_PASS_OUTCOME ; PC,REC,INT CALCULATION ROUTINE (A=DEFENDER VALUE, X=PC OR PC+REC) ⋮ 5577 CMP #TARGET_NOT_CLOSE_INT_THRESHOLD ; VALUE < NO WR INTERCEPTION THRESHOLD 5578 BCC INTERCEPTION_NORMAL ; YES->INTERCEPTION ⋮
Bank21_22_play_commands_on_field_logic.asm lines 5552–5588 at f3bae0e · upstream ↗ 187TARGET_NOT_CLOSE_INT_THRESHOLD = $0EBank21_22_play_commands_on_field_logic.asm line 187 at f3bae0e · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
Sources
Code
- bruddog. 2025. “Tecmo Super Bowl (NES), commented disassembly (bruddog).” Commit f3bae0e. bruddog/Tecmo_Super_Bowl_NES_Disassembly @ f3bae0e · licence, all uses