mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 08:55:38 +00:00
IR codegen: Player 2 controller support
ReadInput now takes an explicit player index (0 = P1, 1 = P2). The IR lowering for ButtonRead threads the player through, and the IR codegen selects the correct zero-page input byte ($01 for P1, $08 for P2). https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
parent
adf50aaa7f
commit
8a6441071e
5 changed files with 17 additions and 10 deletions
|
|
@ -407,8 +407,10 @@ impl<'a> IrCodeGen<'a> {
|
|||
self.load_temp(*x);
|
||||
self.emit(STA, AM::Absolute(base + 3));
|
||||
}
|
||||
IrOp::ReadInput(dest) => {
|
||||
self.emit(LDA, AM::ZeroPage(0x01)); // ZP_INPUT_P1
|
||||
IrOp::ReadInput(dest, player) => {
|
||||
// $01 = P1 input byte, $08 = P2 input byte
|
||||
let addr = if *player == 1 { 0x08 } else { 0x01 };
|
||||
self.emit(LDA, AM::ZeroPage(addr));
|
||||
self.store_temp(*dest);
|
||||
}
|
||||
IrOp::WaitFrame => {
|
||||
|
|
|
|||
|
|
@ -544,11 +544,15 @@ impl LoweringContext {
|
|||
self.emit(IrOp::Call(Some(t), name.clone(), arg_temps));
|
||||
t
|
||||
}
|
||||
Expr::ButtonRead(_, button, _) => {
|
||||
Expr::ButtonRead(player, button, _) => {
|
||||
// Button reads: read the input byte, mask with the button bit.
|
||||
// (Player selection is ignored here; IR codegen handles it.)
|
||||
// Player 1 reads from $01, player 2 reads from $08.
|
||||
let player_index = match player {
|
||||
Some(Player::P2) => 1u8,
|
||||
_ => 0u8,
|
||||
};
|
||||
let input = self.fresh_temp();
|
||||
self.emit(IrOp::ReadInput(input));
|
||||
self.emit(IrOp::ReadInput(input, player_index));
|
||||
let mask = button_mask(button);
|
||||
let mask_temp = self.fresh_temp();
|
||||
self.emit(IrOp::LoadImm(mask_temp, mask));
|
||||
|
|
|
|||
|
|
@ -124,8 +124,9 @@ pub enum IrOp {
|
|||
y: IrTemp,
|
||||
frame: Option<IrTemp>,
|
||||
},
|
||||
/// Read the current player 1 input byte into a temp.
|
||||
ReadInput(IrTemp),
|
||||
/// Read a controller input byte into a temp.
|
||||
/// Second arg: 0 for player 1, 1 for player 2.
|
||||
ReadInput(IrTemp, u8),
|
||||
WaitFrame,
|
||||
Transition(String),
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ fn lower_button_read() {
|
|||
.blocks
|
||||
.iter()
|
||||
.flat_map(|b| &b.ops)
|
||||
.any(|op| matches!(op, IrOp::ReadInput(_)));
|
||||
.any(|op| matches!(op, IrOp::ReadInput(_, _)));
|
||||
assert!(has_input, "button read should emit ReadInput op");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ fn collect_source_temps(op: &IrOp, used: &mut HashSet<IrTemp>) {
|
|||
used.insert(*f);
|
||||
}
|
||||
}
|
||||
IrOp::ReadInput(_) | IrOp::WaitFrame | IrOp::Transition(_) | IrOp::SourceLoc(_) => {}
|
||||
IrOp::ReadInput(_, _) | IrOp::WaitFrame | IrOp::Transition(_) | IrOp::SourceLoc(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ fn op_dest(op: &IrOp) -> Option<IrTemp> {
|
|||
| IrOp::CmpGtEq(d, _, _)
|
||||
| IrOp::ArrayLoad(d, _, _) => Some(*d),
|
||||
IrOp::Call(dest, _, _) => *dest,
|
||||
IrOp::ReadInput(d) => Some(*d),
|
||||
IrOp::ReadInput(d, _) => Some(*d),
|
||||
IrOp::StoreVar(_, _)
|
||||
| IrOp::ArrayStore(_, _, _)
|
||||
| IrOp::DrawSprite { .. }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue