Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Credit to Ownasaurous for constructing/making 90 % this file.
- //rcombs from #tasbot was extremely helpful
- /*
- n64_send function is....
- Copyright (c) 2009 Andrew Brown
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use,
- copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following
- conditions:
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
- */
- int pin = 4;
- int commandNumber = 0;
- int debug = 1;
- int commanddebug = 1;
- inline int port4read()
- {
- return (PIND >> 4) & 1;
- }
- inline void port4OutputMode()
- {
- DDRD = DDRD | B00010000; // force bit/port4 to be 1, which is output mode
- }
- inline void port4InputMode()
- {
- DDRD = DDRD & B11101111; // force bit/port4 to be 0, which is input mode
- }
- inline void port4HIGH()
- {
- PORTD = PORTD | B00010000; // force bit/port4 to be 1 which is HIGH
- }
- inline void port4LOW()
- {
- PORTD = PORTD & B11101111; // force bit/port4 to be 1 which is LOW
- }
- inline void wait1us()
- {
- asm volatile("nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n nop\n"); // 16 nops = 1 us
- }
- static unsigned char n64_buffer[33];
- #define N64_HIGH DDRD &= ~0x10
- #define N64_LOW DDRD |= 0x10
- #define N64_INPUT DDRD &= 0xEF
- #define N64_OUTPUT DDRD |= 0x10
- #define N64_QUERY (PIND & 0x10)
- void setup()
- {
- noInterrupts();
- port4InputMode();
- //Serial.begin(9600);
- }
- void loop()
- {
- unsigned int cmd = readCommand();
- wait1us();
- //wait1us(); // this one is probably not needd because of readCommand overhead
- port4OutputMode();
- switch (cmd)
- {
- case 0x00:
- case 0xFF:
- // send identity, normal controller
- n64_buffer[0] = 0x05;
- n64_buffer[1] = 0x00;
- n64_buffer[2] = 0x01;
- n64_send(n64_buffer, 3, 0);
- break;
- case 0x01:
- // send blank controller data
- n64_buffer[0] = 0x00;
- n64_buffer[1] = 0x00;
- n64_buffer[2] = 0x00;
- n64_buffer[3] = 0x00;
- n64_send(n64_buffer, 4, 0);
- break;
- default:
- break;
- }
- port4InputMode();
- }
- /**
- * Complete copy and paste of gc_send, but with the N64
- * pin being manipulated instead.
- */
- static void n64_send(unsigned char *buffer, char length, bool wide_stop)
- {
- asm volatile (";Starting N64 Send Routine");
- // Send these bytes
- char bits;
- // This routine is very carefully timed by examining the assembly output.
- // Do not change any statements, it could throw the timings off
- //
- // We get 16 cycles per microsecond, which should be plenty, but we need to
- // be conservative. Most assembly ops take 1 cycle, but a few take 2
- //
- // I use manually constructed for-loops out of gotos so I have more control
- // over the outputted assembly. I can insert nops where it was impossible
- // with a for loop
- asm volatile (";Starting outer for loop");
- outer_loop:
- {
- asm volatile (";Starting inner for loop");
- bits=8;
- inner_loop:
- {
- // Starting a bit, set the line low
- asm volatile (";Setting line to low");
- N64_LOW; // 1 op, 2 cycles
- asm volatile (";branching");
- if (*buffer >> 7) {
- asm volatile (";Bit is a 1");
- // 1 bit
- // remain low for 1us, then go high for 3us
- // nop block 1
- asm volatile ("nop\nnop\nnop\nnop\nnop\n");
- asm volatile (";Setting line to high");
- N64_HIGH;
- // nop block 2
- // we'll wait only 2us to sync up with both conditions
- // at the bottom of the if statement
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- );
- } else {
- asm volatile (";Bit is a 0");
- // 0 bit
- // remain low for 3us, then go high for 1us
- // nop block 3
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\n");
- asm volatile (";Setting line to high");
- N64_HIGH;
- // wait for 1us
- asm volatile ("; end of conditional branch, need to wait 1us more before next bit");
- }
- // end of the if, the line is high and needs to remain
- // high for exactly 16 more cycles, regardless of the previous
- // branch path
- asm volatile (";finishing inner loop body");
- --bits;
- if (bits != 0) {
- // nop block 4
- // this block is why a for loop was impossible
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n");
- // rotate bits
- asm volatile (";rotating out bits");
- *buffer <<= 1;
- goto inner_loop;
- } // fall out of inner loop
- }
- asm volatile (";continuing outer loop");
- // In this case: the inner loop exits and the outer loop iterates,
- // there are /exactly/ 16 cycles taken up by the necessary operations.
- // So no nops are needed here (that was lucky!)
- --length;
- if (length != 0) {
- ++buffer;
- goto outer_loop;
- } // fall out of outer loop
- }
- // send a single stop (1) bit
- // nop block 5
- asm volatile ("nop\nnop\nnop\nnop\n");
- N64_LOW;
- // wait 1 us, 16 cycles, then raise the line
- // take another 3 off for the wide_stop check
- // 16-2-3=11
- // nop block 6
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\n");
- if (wide_stop) {
- asm volatile (";another 1us for extra wide stop bit\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n");
- }
- N64_HIGH;
- }
- unsigned int readCommand()
- {
- unsigned int command = readn64(), bits = 1;
- while (true)
- {
- command = command << 1;
- command += readn64();
- command &= 0x1FF;
- bits++;
- if (bits >= 9)
- {
- if (command == 0x3 || command == 0x1 || command == 0x1FF || command == 0x5 || command == 0x7)
- {
- command = command >> 1;
- if (commanddebug == 1)
- {
- commandNumber++;
- char buff[256];
- sprintf(buff,"Command #%d = 0x%02X",commandNumber,command);
- Serial.println(buff);
- }
- return command;
- }
- }
- }
- }
- unsigned int readn64()
- {
- while (true)
- {
- if (N64_QUERY)
- break;
- }
- while (true)
- {
- if (!N64_QUERY)
- break;
- }
- wait1us();
- wait1us();
- if (debug == 1)
- {
- Serial.print("Bit: ");
- //Serial.print(port4read());
- Serial.println("");
- }
- return N64_QUERY;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement