Advertisement
dkonigsberg

nestronic

Feb 19th, 2018
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;;;;;;;;;;;;;;;;;;;;;;;;
  2. ; NEStronic Code for the NES CPU (RP2A03)
  3. ;;;;;;;;;;;;;;;;;;;;;;;;
  4.  
  5. .import __STACK_START__, __STACK_SIZE__
  6. .include "zeropage.inc"
  7. .include "nes.inc"
  8.  
  9. ;
  10. ; Definitions
  11. ;
  12.  
  13. ; PCA9564 Registers
  14. PCA_STA         = $6000 ; Status (R)
  15. PCA_TO          = $6000 ; Time-out (W)
  16. PCA_DAT         = $6001 ; Data (R/W)
  17. PCA_ADR         = $6002 ; Own address (R/W)
  18. PCA_CON         = $6003 ; Control (R/W)
  19.  
  20. ; PCA9564 Clock speeds
  21. PCA_CON_330kHz  = $00
  22. PCA_CON_288kHz  = $01
  23. PCA_CON_217kHz  = $02
  24. PCA_CON_146kHz  = $03
  25. PCA_CON_88kHz   = $04
  26. PCA_CON_59kHz   = $05
  27. PCA_CON_44kHz   = $06
  28. PCA_CON_36kHz   = $07
  29.  
  30. ; PCA9564 Control flags
  31. PCA_CON_AA      = $80 ; Assert Acknowledge
  32. PCA_CON_ENSIO   = $40 ; Enable
  33. PCA_CON_STA     = $20 ; Start
  34. PCA_CON_STO     = $10 ; Stop
  35. PCA_CON_SI      = $08 ; Serial Interrupt
  36. PCA_CON_CR      = $07 ; Clock Rate (MASK)
  37.  
  38. ; I2C Commands
  39. CMD_OUT         = $16 ; Output pin control
  40. CMD_APU         = $40 ; APU register write
  41.  
  42. .segment "ZEROPAGE"
  43. ; Variables go here
  44. cmd_len: .res 1
  45. cmd_buf: .res 7
  46.  
  47. .segment "STARTUP"
  48.  
  49. .segment "CODE"
  50. start:
  51.     sei     ; Ignore IRQs
  52.     cld     ; Disable decimal mode
  53.  
  54.     ; Setup the stack
  55.     ldx #$FF
  56.     txs
  57.  
  58.     ; Initialize the APU
  59.     jsr init_apu
  60.  
  61.     ; Wait a little bit
  62.     ldy #20
  63.     jsr delay_y_frames
  64.  
  65.     jsr i2c_init
  66.  
  67. @cmd_loop:
  68.     jsr i2c_slave_cmd
  69.  
  70.     lda cmd_len         ; Check the command length
  71.     cmp #0
  72.     beq @cmd_loop       ; Loop around if zero
  73.  
  74.     lda cmd_buf         ; Check the first command byte
  75.  
  76.     cmp #CMD_OUT        ; Output pin control
  77.     beq @out_cmd
  78.  
  79.     cmp #CMD_APU        ; APU register write
  80.     beq @apu_cmd
  81.  
  82.     jmp @cmd_loop
  83.  
  84. @out_cmd:
  85.     lda cmd_len
  86.     cmp #2              ; Check for 1 argument
  87.     bne @cmd_loop
  88.  
  89.     ldx #1              ; Index the argument
  90.     lda cmd_buf, X      ; Load the argument
  91.  
  92.     sta $4016           ; Store the argument in the OUT register
  93.  
  94.     jmp @cmd_loop
  95.  
  96. @apu_cmd:
  97.     lda cmd_len
  98.     cmp #3              ; Check for 2 arguments
  99.     bne @cmd_loop
  100.  
  101.     ldx #1              ; Index the register argument
  102.     ldy cmd_buf, X      ; Load the register argument into Y
  103.  
  104.     ldx #2              ; Index the value argument
  105.     lda cmd_buf, X      ; Load the data argument into A
  106.  
  107.     sta $4000, Y        ; Store A in $4000+Y
  108.  
  109.     jmp @cmd_loop
  110.  
  111. forever:
  112.     jmp forever    ; loop forever to halt
  113.  
  114. ;
  115. ; Initializes APU registers and silences all channels
  116. ; Note: This will stomp on $4016, which can cause issues for our testing
  117. ;
  118. init_apu:
  119.     lda #$0F
  120.     sta $4015
  121.    
  122.     ldy #0
  123. :       lda @regs,y
  124.     sta $4000,y
  125.     iny
  126.     cpy #$18
  127.     bne :-
  128.    
  129.     rts
  130. @regs:
  131.     .byte $30,$7F,$00,$00
  132.     .byte $30,$7F,$00,$00
  133.     .byte $80,$00,$00,$00
  134.     .byte $30,$00,$00,$00
  135.     .byte $00,$00,$00,$00
  136.     .byte $00,$0F,$00,$C0
  137.  
  138. ;
  139. ; Initialize the PCA9564 I2C Controller
  140. ;
  141. i2c_init:
  142.     lda #$FF
  143.     sta PCA_TO          ; Set timeout
  144.     lda #($08 << 1)
  145.     sta PCA_ADR         ; Set own address to $08
  146.     lda #(PCA_CON_ENSIO | PCA_CON_330kHz)
  147.     sta PCA_CON         ; Enable serial I/O
  148.     nop                 ; Wait for oscillator startup
  149.     nop
  150.     lda #(PCA_CON_AA | PCA_CON_ENSIO | PCA_CON_330kHz)
  151.     sta PCA_CON         ; Start as slave
  152.     rts
  153.  
  154. ;
  155. ; Wait for the I2C interrupt flag to be set
  156. ;
  157. i2c_wait_busy:
  158.     ; TODO: store a timeout counter somewhere
  159. @loop:
  160.     lda PCA_CON         ; Load the current value of I2CCON
  161.     and #PCA_CON_SI     ; Mask the SI bit
  162.     cmp #PCA_CON_SI     ; Check if the SI bit is set
  163.     ; TODO: decrement a timer counter. and fail if zero
  164.     bne @loop           ; If not set, then loop
  165.     rts
  166.  
  167. ;
  168. ; Wait as an I2C slave for the next command
  169. ;
  170. i2c_slave_cmd:
  171.     ldx #$00
  172.     stx cmd_len         ; Zero out the command length
  173.  
  174.     jsr i2c_wait_busy   ; Wait for SI
  175.  
  176.     lda PCA_STA
  177.     cmp #$60            ; Own SLA+W has been received
  178.     beq @receiver
  179.     cmp #$A8            ; Own SLA+R has been received
  180.     beq @transmitter
  181.     jmp @fault
  182.  
  183. @receiver:
  184.     lda #(PCA_CON_AA | PCA_CON_ENSIO | PCA_CON_330kHz)
  185.     sta PCA_CON         ; Reset SI bit
  186.  
  187.     jsr i2c_wait_busy
  188.  
  189.     lda PCA_STA
  190.     cmp #$80            ; Data has been received
  191.     bne @receiver_done
  192.  
  193.     lda PCA_DAT
  194.     sta cmd_buf, X      ; Store the data byte
  195.     inx                 ; Increment the length counter
  196.     cpx #8              ; Check for the max command length
  197.     beq @fault          ; Fault if we received too many bytes
  198.  
  199.     jmp @receiver
  200.  
  201. @receiver_done:
  202.     lda PCA_STA
  203.     cmp #$A0            ; A STOP condition has been received
  204.     bne @fault
  205.     stx cmd_len         ; Store the command length
  206.     jmp @done
  207.  
  208. @transmitter:
  209.     ; TODO: Mode not yet supported, this is placeholder code
  210.     lda #$FF
  211.     sta PCA_DAT         ; Load dummy data
  212.  
  213.     lda #(PCA_CON_AA | PCA_CON_ENSIO | PCA_CON_330kHz)
  214.     sta PCA_CON         ; Reset SI bit
  215.  
  216.     jsr i2c_wait_busy
  217.  
  218.     lda PCA_STA
  219.     cmp #$B8            ; Data byte in I2CDAT has been transmitted (ACK)
  220.     ; TODO: Loop to @transmitter and send next byte
  221.     cmp #$C0            ; Data byte in I2CDAT has been transmitted (NACK)
  222.     bne @fault
  223.  
  224. @transmitter_done:
  225.     jmp @done
  226.  
  227. @fault:
  228.     ; figure out what to do in a fault condition
  229.  
  230. @done:
  231.     lda #(PCA_CON_AA | PCA_CON_ENSIO | PCA_CON_330kHz)
  232.     sta PCA_CON         ; Reset SI bit
  233.     rts
  234.  
  235. ;
  236. ; Delays Y/60 second
  237. ;
  238. delay_y_frames:
  239. :       jsr delay_frame
  240.     dey
  241.     bne :-
  242.     rts
  243.  
  244. ;
  245. ; Delays 1/60 second
  246. ;
  247. delay_frame:
  248.     ; delay 29816
  249.     lda #67
  250. :       pha
  251.     lda #86
  252.     sec
  253. :       sbc #1
  254.     bne :-
  255.     pla
  256.     sbc #1
  257.     bne :--
  258.     rts
  259. ;
  260. ; Handle interrupts by doing nothing
  261. ;
  262. nmi:
  263. irq:
  264.     rti
  265.  
  266. .segment "RODATA"
  267. ; Static data goes here
  268.  
  269. .segment "VECTORS"
  270. .word nmi   ;$FFFA NMI
  271. .word start ;$FFFC Reset
  272. .word irq   ;$FFFE IRQ
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement