Permalink
Browse files

Added initial int0 vector in assembly

The problem was that it appeared that it was taking too long to
execute the interrupt handler in c and so the int0 interrupt would
get called before int0 was called 8 times and reset the read mask.

The solution was to write the ISR for INT0 in assembly, trying to
optimize as best as possible to get the instructions. Also, the clock
was changed to be a 20Mhz crystal to get us some more time. According
to http://store.curiousinventor.com/guides/PS2/, for the PS1, the
bus frequency is between 100Khz and 500Khz. This gives about 8-24 ish
cycles before the next clock begins. In addition, the send queue was
abandoned in favor of using a single byte and mask for both send and
receive. For simplicity, it is assumed that when the mask is nonzero,
it is sending/receiving. Once the mask is entirely shifted off, the
byte has been sent/received, and so the ISR can ignore anything past
that point.
  • Loading branch information...
kcuzner committed Aug 4, 2013
1 parent 7d15e6f commit 51bb37af031981c1c2d462e4d710d83551b1e87e
Showing with 149 additions and 113 deletions.
  1. +2 −0 .gitignore
  2. +2 −2 Makefile
  3. +1 −10 include/psx.h
  4. +24 −0 include/psx_pins.h
  5. +25 −101 src/psx.c
  6. +95 −0 src/psx_fast.S
View
@@ -5,6 +5,8 @@
*.hex
*.lst
+obj
+
#sublime files
*.sublime-workspace
View
@@ -85,15 +85,15 @@ PROJECTNAME=popnmusic
# (list all files to compile, e.g. 'a.c b.cpp as.S'):
# Use .cc, .cpp or .C suffix for C++ files, use .S
# (NOT .s !!!) for assembly source code files.
-PRJSRC=src/main.c src/psx.c src/buttons.c
+PRJSRC=src/main.c src/psx.c src/buttons.c src/psx_fast.S
# additional includes (e.g. -I/path/to/mydir)
INC=-Iinclude
# libraries to link in (e.g. -lmylib)
LIBS=
-F_CPU=8000000
+F_CPU=20000000
# Optimization level,
# use s (size opt), 1, 2, 3 or 0 (off)
View
@@ -14,17 +14,8 @@
#ifndef _PSX_H_
#define _PSX_H_
+#include "psx_pins.h"
#include <stdint.h>
-
-#define PSX_PORT PORTD
-#define PSX_PIN PIND
-#define PSX_DDR DDRD
-#define PSX_ATT_MASK 1 << PD3
-#define PSX_CLK_MASK 1 << PD2
-#define PSX_DATA_MASK 1 << PD1
-#define PSX_CMD_MASK 1 << PD0
-#define PSX_ACK_MASK 1 << PD4
-
/**
* PSX bus setup function
*/
View
@@ -0,0 +1,24 @@
+/**
+ * Pins file for psx bus
+ */
+
+#ifndef _PSX_PINS_H_
+#define _PSX_PINS_H_
+
+#define PSX_PORT PORTD
+#define PSX_PIN PIND
+#define PSX_DDR DDRD
+
+#define PSX_ATT PD3
+#define PSX_CLK PD2
+#define PSX_DATA PD1
+#define PSX_CMD PD0
+#define PSX_ACK PD4
+
+#define PSX_ATT_MASK 1 << PD3
+#define PSX_CLK_MASK 1 << PD2
+#define PSX_DATA_MASK 1 << PD1
+#define PSX_CMD_MASK 1 << PD0
+#define PSX_ACK_MASK 1 << PD4
+
+#endif
View
126 src/psx.c
@@ -7,26 +7,31 @@
#include <avr/io.h>
#include <avr/interrupt.h>
-static const uint8_t ATT_SIGNALED = 1 << 1;
-static const uint8_t RECEIVED_READY = 1 << 2;
-
-static volatile uint8_t sendSize, sendIndex, sendMask;
-static volatile uint8_t sendBuffer[5];
-static volatile uint8_t recvMask, recvBuffer;
-static volatile uint8_t received;
+/**
+ * The following variables are required by the psx_fast file which contains
+ * our ISRs so that they run reasonably
+ *
+ * As an optimization, they work as follows
+ * Send:
+ * - A byte is queued to be sent by setting sendByte to the value and sendMask to 0x01
+ * - If the sendMask != 0 when queuing occurs, it returns false
+ * - If sendMask != 0, the ISR ands the byte with the sendmask, sets data accordingly, and shifts sendMask left, no rotate
+ */
-static volatile uint8_t flags;
+volatile uint8_t sendByte, sendMask;
+volatile uint8_t recvByte, recvMask;
+volatile uint8_t flags;
void psx_setup(void)
{
+ unsigned char i;
//reset all flags
flags = 0;
//set up buffers
- sendSize = sendIndex = 0;
- sendMask = 0x01;
- recvBuffer = received = 0;
- recvMask = 0x01;
+ sendByte = sendMask = 0;
+ recvByte = recvMask = 0;
+ flags = 0;
//set up the direction
PSX_DDR &= ~(PSX_ATT_MASK | PSX_CLK_MASK);
@@ -45,106 +50,25 @@ void psx_ack(void)
char psx_send(uint8_t data)
{
- if (sendSize == 5) {
+ if (sendMask != 0x00)
+ {
return 0;
}
- sendBuffer[sendSize] = data;
-
- sendSize++;
-
- return sendSize;
+ sendByte = data;
+ sendMask = 0x01; //tell it to start
}
/**
* PSX_ATT falls low
*/
ISR(INT1_vect)
{
- //reset our transmission state
- sendSize = 0; //we set this first so thing is transmitted
- sendIndex = 0;
- sendMask = 0x01;
-
- if (recvMask == 0x20) {
- PORTB = 0x08;
+ if (recvMask != 0x00) {
+ PORTB |= 0x08;
}
- //reset our receive state
- recvBuffer = 0;
+ //start receive
+ recvByte = 0;
recvMask = 0x01;
-
- //notify that we have had our attention called
- //psx_on_att();
-}
-
-/**
- * PSX_CLK rises high or falls low
- */
-ISR(INT0_vect)
-{
- if (!(PSX_PIN & PSX_ATT_MASK))
- {
- //this isn't meant for us
- return;
- }
-
- if (PSX_PIN & PSX_CLK_MASK)
- {
- //rising edge: we read cmd
- if (PSX_PIN & PSX_CMD_MASK)
- {
- //recvBuffer |= recvMask;
- }
-
- if (recvMask == 0x80) {
-
- }
-
- if (recvMask == 0x80) //we finished
- {
- received = recvBuffer; //copy what we got
- recvBuffer = 0; //reset the buffer
- recvMask = 0x01; //reset the mask
- //flags |= RECEIVED_READY;
- }
- else
- {
- recvMask = recvMask << 1; //shift over for next bit
- }
- }
- else
- {
- //falling edge: we write data
- if (sendIndex >= sendSize)
- {
- //nothing to send
- return;
- }
-
- if (sendBuffer[sendIndex] & sendMask)
- {
- //data becomes input with pull up
- PSX_DDR &= ~PSX_DATA_MASK;
- PSX_PORT |= PSX_DATA_MASK;
- }
- else
- {
- //data pulled low
- PSX_DDR |= PSX_DATA_MASK;
- PSX_PORT &= ~PSX_DATA_MASK;
- }
-
- if (sendMask == 0x80)
- {
- //next byte
- sendMask = 0x01;
- sendIndex++;
- }
- else
- {
- //increment send mask
- sendMask <<= 1;
- }
- }
}
View
@@ -0,0 +1,95 @@
+/**
+ * Fast interrupts for psx bus since C can't seem to get it right
+ *
+ * Assembly is the very definition of speghetti code...hopefully it can be
+ * avoided
+ */
+
+#include <avr/io.h>
+#include "psx_pins.h"
+
+#define sreg_save r2
+
+;; Byte to send (psx.c)
+.extern sendByte
+;; Mask for current bit sending (psx.c)
+.extern sendMask
+;; Byte received (psx.c)
+.extern recvByte
+;; Mask for current bit receiving (psx.c)
+.extern recvMask
+
+
+/**
+ * INT0 vector
+ *
+ * This happens on any change, this is for reading cmd or writing data
+ */
+.global INT0_vect
+INT0_vect:
+ in sreg_save, _SFR_IO_ADDR(SREG)
+
+ ;; Save working registers
+ push r24
+ push r25
+
+ ;;if ATT is set, we end since its not talking to us
+ sbis _SFR_IO_ADDR(PSX_PIN), PSX_ATT
+ rjmp INT0_vect_done
+
+ ;;if CLK is high, we are reading CMD. Otherwise, we are writing DATA
+ sbic _SFR_IO_ADDR(PSX_PIN), PSX_CLK
+ rjmp INT0_vect_read
+
+ INT0_vect_write:
+ ;;load sendByte and AND it with sendMask. If sendMask == 0, we are done
+ lds r25, sendMask
+ andi r25, 0xFF
+ breq INT0_vect_done
+ lds r24, sendByte
+ and r24, r25
+ ;;if result of AND is 0, pull data low
+ breq INT0_vect_data_low
+
+ INT0_vect_write_high:
+ ;;we allow data to float high by clearing the ddr
+ cbi _SFR_IO_ADDR(PSX_DDR), PSX_DATA
+
+ rjmp INT0_vect_write_shift
+ INT0_vect_write_low:
+ ;;we bring data low by making it an output and setting it low
+ sbi _SFR_IO_ADDR(PSX_DDR), PSX_DATA
+ cbi _SFR_IO_ADDR(PSX_PORT), PSX_DATA
+
+ INT0_vect_write_shift:
+ ;;as a final step to all writes, we shift the mask over (still in r25)
+ lsl r25
+ sts sendMask, r25
+
+ rjmp INT0_vect_done
+
+ INT0_vect_read:
+ ;;load recvMask. If == 0, we are done
+ lds r25, recvMask
+ andi r25, 0xFF
+ breq INT0_vect_done
+ ;;we load the send byte
+ lds r24, recvByte
+ ;;if cmd is set, we or the mask with the byte and either way, store the result
+ sbic _SFR_IO_ADDR(PSX_PIN), PSX_CMD
+ or r24, r25
+ sts recvByte, r24
+ ;;we shift the mask (r25) and store it
+ lsl r25
+ ;brne INT0_vect_read_store
+
+ INT0_vect_read_store:
+ sts recvMask, r25
+
+ ;;finishing int0
+ INT0_vect_done:
+ pop r25
+ pop r24
+ out _SFR_IO_ADDR(SREG), sreg_save
+ reti
+

0 comments on commit 51bb37a

Please sign in to comment.