rumble_support.txt
7.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
RUMBLE PACK SUPPORT
In order to support the rumble pak directly through hardware our
SI implementation would need to support a set of commands issued
through the DMA channel. The goal of the following analysis is to
pinpoint the minimal set of commands the SI would be required to
support. Because we already support block commands (see below),
it is the single channel commands that are of primary interest
here.
As a basis for analyzing the rumble pak requirements, the
motortest application shipped with the n64 SKD has been run and
traced. The motortest code flow is given below, but is preceded
by a summary of the SI single channel commands we would need to
support. The code flow will show where and how the various single
channel commands are issued, succeed and fail.
Here is a quick review of the two types of PIF/SI commands:
block command - a command issued to the SI formatted to
simultaneously address every controller (max of 4). The
format uses 8 bytes per controller and the response will
also fit within 8 bytes per controller.
single channel command - a command issued to address a single
controller. The command specifies the controller by starting
the transferred memory block with (controller_number - 1)
zeroes, where controller numbering begins at zero. Then, a
data structure conveying the actual command is issued,
followed by a command ending marker. The command specifies
the number of bytes to recieve. Received data is in the same
data format (along with preceding 0x00 bytes for channel
indexing), and the rxsize parameter of every data structure
holds the failure indicator bits in the upper nibble.
SUMMARY OF SINGLE CHANNEL COMMANDS REQUIRED
-------------------------------------------
1) Data structure __OSContRequestFormatShort, with parameters
txsize = 1
rxsize = 3
cmd = CONT_REQUEST
typeh = 0xff
typel = 0xff
status = 0xff
2) Data structure __OSContRamReadFormat, with parameters
dummy = 0xff
txsize = 35
rxsize = 1
cmd = CONT_RAM_WRITE
addrh --> these hold address 0x8000/BLOCKSIZE passed in,
addrl along with address CRC.
data = can take on various values, see CODE FLOW below.
datacrc = 0xff
The datacrc must be set correctly on return.
NOTE: we can also have the above with address fields:
addrh --> these hold address 0xc000/BLOCKSIZE (M_ADDR),
addrl along with address CRC.
3) Data structure __OSContRamReadFormat, with parameters
dummy = 0xff
txsize = 3
rxsize = 33
cmd = CONT_RAM_READ
addrh --> these hold address 0x8000/BLOCKSIZE passed in,
addrl along with address CRC.
data --> set on return
datacrc = 0xff
The datacrc must be set correctly on return.
CODE FLOW
---------
osContInit() --> issues a block command
osPfsInitPak()
__osPfsGetStatus()
__osPfsRequestOneChannel()
+ fills a single channel request buffer of type
__OSContRequesFormatShort.
Values are:
txsize = 1
rxsize = 3
cmd = CONT_REQUEST
typeh = 0xff
typel = 0xff
status = 0xff
+ issues DMA's to produce command issue/response
__osPfsGetOneChannelData()
+ retrieves response to previous request that has 0x00
bytes prepended for each channel, followed by type
__OSContRequesFormatShort.
+ insure success by checking upper bits of rxsize returned.
+ return success
__osPfsCheckRamArea()
__osPfsSelectBank(--bank=0x00--)
+ fill a buffer (u8 temp[BLOCKSIZE], BLOCKSIZE=0x20) with 0x00
bytes, where the 0x00 was passed in as the "bank" argument.
__osContRamWrite()
+ Issues single channel command with type
__OSContRamReadFormat.
Values are:
dummy = 0xff
txsize = 35
rxsize = 1
cmd = CONT_RAM_WRITE
addrh --> these hold address 0x8000/BLOCKSIZE passed in,
addrl along with address CRC.
data = array passed in full of 0x00 bytes
datacrc = 0xff
+ issues DMA's to produce command issue/response
+ retieve response data of format __OSContRamReadFormat
+ insure success by checking upper rxsize bits returned
+ insure returned datacrc is same as locally computed version
+ return success
+ return success
__osContRamRead() --> to save data overwritten by ensuing test
+ Issues single channel command with type __OSContRamReadFormat.
Values are:
dummy = 0xff
txsize = 3
rxsize = 33
cmd = CONT_RAM_READ
addrh --> these hold address 0x8000/BLOCKSIZE passed in,
addrl along with address CRC.
data --> filled in on return.
datacrc = 0xff
+ issues DMA's to produce command issue/response
+ retieve response data of format __OSContRamReadFormat
+ insure success by checking upper rxsize bits returned
+ insure returned datacrc is same as locally computed version
+ return success
+ setup test data for write to Ram
__osContRamWrite() --> write the test data pattern
__osContRamRead() --> read back the test pattern
+ compare result of readback with known data written previously.
This fails.
+ return PFS_ERR_DEVICE
+ returns PFS_ERR_DEVICE
+ detect PFS_ERR_DEVICE, specifically (i.e., no other error will allow
us to continue).
osMotorInit()
__osPfsSelectBank(--bank=CHECK_ID, which is 0xfe--)
+ insure previous call success
__osContRamRead(--address=BANK_ADDR, which is 0x8000/BLOCKSIZE--)
+ insure previous call success
__osPfsSelectBank(--bank=MOTOR_ID, which is 0x80--)
+ insure previous call success
__osContRamRead(--address=BANK_ADDR, which is 0x8000/BLOCKSIZE--)
+ insure previous call success
+ insure data read has last byte = MOTOR_ID
__osMakeMotorData()
+ sets up a global for this channel's use to issue commands. The
data is of type __OSContRamReadFormat. This will be used
to issue future commands, which just change the actual
data, but not the parameters. Values are:
dummy = 0xff
txsize = 35
rxsize = 1
cmd = CONT_RAM_WRITE
addrh --> these hold address 0xc000/BLOCKSIZE (M_ADDR),
addrl along with address CRC.
data --> will be filled by actual start/stop commands.
datacrc --> will be filled by actual start/stop commands.
osMotorStart()
__osMotorAccess(--flag=1--)
+ fill data portion of motor command setup in __osMakeMotorData()
with all values = flag, so 0x01.
+ issue DMA's to trigger PIF (return data is __OSContRamReadFormat).
+ insure no error by checking upper bits of rxsize returned.
+ insure returned datacrc is 0x00 for flag=0, and 0xeb for flag=1.
osMotorStop()
__osMotorAccess(--flag=0--)