Created
April 2, 2020 22:56
-
-
Save IshanArya/4456f582f500f88744576d4fa0607d41 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ; This program uses the SLOW_SRAM device to write and read some | |
| ; values from the DE2 external SRAM chip. It reads a value from | |
| ; the switches, and stores THAT value at THAT address. Then, it | |
| ; runs an endless loop where it reads the switches and displays | |
| ; the value at that address on the left seven-segment displays. | |
| ; If DE2 is powered off, then on, then this program is run with | |
| ; the switches set for 0000, then it will display 0000, but if | |
| ; the switches are moved to other values, it will display the | |
| ; random data still at those locations. | |
| ; Resetting the DE2 and running again, without powering off, | |
| ; allows the user to write one new value each time. | |
| ; Limitations: | |
| ; - cannot specify an address over 16-bits | |
| ; - not a particularly good way to test a lot of locations | |
| ; - uses the SLOW_SRAM device, taking 9-12 instructions for | |
| ; a single read or write | |
| ; This program includes... | |
| ; - Several useful subroutines (ATAN2, Neg, Abs, mult, div). | |
| ; - Some useful constants (masks, numbers, robot stuff, etc.) | |
| ORG 0 | |
| ;*************************************************************** | |
| ;* Main code | |
| ;*************************************************************** | |
| Main: | |
| LOADI &B011 | |
| OUT SRAM_CTRL ; 011 = no drive, no write, no read | |
| ; Set the address to 5 | |
| LOADI 0 | |
| OUT SRAM_ADHI | |
| LOADI 5 | |
| OUT SRAM_ADLOW | |
| ; Write a value | |
| LOADI 10 | |
| OUT SRAM_DATA | |
| LOADI &B101 | |
| OUT SRAM_CTRL ; 101 = drive, write, no OE(no read) | |
| LOADI &B111 | |
| OUT SRAM_CTRL ; 111 = drive, no write, no OE(no read) | |
| LOADI &B011 | |
| OUT SRAM_CTRL ; 011 = no drive, no write, no read | |
| ; Write a value incorrectly | |
| LOADI 6 | |
| OUT SRAM_ADLOW | |
| LOADI 11 | |
| OUT SRAM_DATA | |
| LOADI &B101 | |
| OUT SRAM_CTRL ; 101 = drive, write, no OE(no read) | |
| ; NOTE: Changing the address mid-write is NOT SAFE, because it | |
| ; might overwrite data in addresses other than the two you're | |
| ; changing between. It's done here just to confirm that the | |
| ; emulated SRAM chip behaves similarly to real SRAM. | |
| LOADI 7 | |
| OUT SRAM_ADLOW ; Change the address mid-write | |
| LOADI 8 | |
| OUT SRAM_ADLOW ; Change the address mid-write | |
| ; NOTE: Changing the data mid-write IS safe, because it | |
| ; will simply overwrite the previous data. The data in | |
| ; the SRAM remains fluid until WE_N is deasserted, at which | |
| ; point the data is fixed. | |
| LOADI 12 | |
| OUT SRAM_DATA ; Change the data mid-write | |
| LOADI &B111 | |
| OUT SRAM_CTRL ; 111 = drive, no write, no OE(no read) | |
| LOADI &B011 | |
| OUT SRAM_CTRL ; 011 = no drive, no write, no read | |
| ; Read a value from address 0x105 | |
| LOADI &H105 | |
| OUT SRAM_ADLOW | |
| LOADI &B10 | |
| OUT SRAM_CTRL | |
| IN SRAM_DATA ; Data will be in AC after this | |
| LOADI &B11 | |
| OUT SRAM_CTRL | |
| ; Read the previously-written values from addresses 5-8 | |
| LOADI 5 | |
| OUT SRAM_ADLOW | |
| LOADI &B10 | |
| OUT SRAM_CTRL | |
| IN SRAM_DATA ; Data will be in AC after this | |
| LOADI 6 | |
| OUT SRAM_ADLOW | |
| IN SRAM_DATA ; Data will be in AC after this | |
| LOADI 7 | |
| OUT SRAM_ADLOW | |
| IN SRAM_DATA ; Data will be in AC after this | |
| LOADI 8 | |
| OUT SRAM_ADLOW | |
| IN SRAM_DATA ; Data will be in AC after this | |
| LOADI &B11 | |
| OUT SRAM_CTRL | |
| Done: | |
| JUMP Done | |
| ;******************************************************************************* | |
| ; Mod360: modulo 360 | |
| ; Returns AC%360 in AC | |
| ; Written by Kevin Johnson. No licence or copyright applied. | |
| ;******************************************************************************* | |
| Mod360: | |
| ; easy modulo: subtract 360 until negative then add 360 until not negative | |
| JNEG M360N | |
| ADDI -360 | |
| JUMP Mod360 | |
| M360N: | |
| ADDI 360 | |
| JNEG M360N | |
| RETURN | |
| ;******************************************************************************* | |
| ; Abs: 2's complement absolute value | |
| ; Returns abs(AC) in AC | |
| ; Neg: 2's complement negation | |
| ; Returns -AC in AC | |
| ; Written by Kevin Johnson. No licence or copyright applied. | |
| ;******************************************************************************* | |
| Abs: | |
| JPOS Abs_r | |
| Neg: | |
| XOR NegOne ; Flip all bits | |
| ADDI 1 ; Add one (i.e. negate number) | |
| Abs_r: | |
| RETURN | |
| ;******************************************************************************; | |
| ; Atan2: 4-quadrant arctangent calculation ; | |
| ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; | |
| ; Original code by Team AKKA, Spring 2015. ; | |
| ; Based on methods by Richard Lyons ; | |
| ; Code updated by Kevin Johnson to use software mult and div ; | |
| ; No license or copyright applied. ; | |
| ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; | |
| ; To use: store dX and dY in global variables AtanX and AtanY. ; | |
| ; Call Atan2 ; | |
| ; Result (angle [0,359]) is returned in AC ; | |
| ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; | |
| ; Requires additional subroutines: ; | |
| ; - Mult16s: 16x16->32bit signed multiplication ; | |
| ; - Div16s: 16/16->16R16 signed division ; | |
| ; - Abs: Absolute value ; | |
| ; Requires additional constants: ; | |
| ; - One: DW 1 ; | |
| ; - NegOne: DW 0 ; | |
| ; - LowByte: DW &HFF ; | |
| ;******************************************************************************; | |
| Atan2: | |
| LOAD AtanY | |
| CALL Abs ; abs(y) | |
| STORE AtanT | |
| LOAD AtanX ; abs(x) | |
| CALL Abs | |
| SUB AtanT ; abs(x) - abs(y) | |
| JNEG A2_sw ; if abs(y) > abs(x), switch arguments. | |
| LOAD AtanX ; Octants 1, 4, 5, 8 | |
| JNEG A2_R3 | |
| CALL A2_calc ; Octants 1, 8 | |
| JNEG A2_R1n | |
| RETURN ; Return raw value if in octant 1 | |
| A2_R1n: ; region 1 negative | |
| ADDI 360 ; Add 360 if we are in octant 8 | |
| RETURN | |
| A2_R3: ; region 3 | |
| CALL A2_calc ; Octants 4, 5 | |
| ADDI 180 ; theta' = theta + 180 | |
| RETURN | |
| A2_sw: ; switch arguments; octants 2, 3, 6, 7 | |
| LOAD AtanY ; Swap input arguments | |
| STORE AtanT | |
| LOAD AtanX | |
| STORE AtanY | |
| LOAD AtanT | |
| STORE AtanX | |
| JPOS A2_R2 ; If Y positive, octants 2,3 | |
| CALL A2_calc ; else octants 6, 7 | |
| CALL Neg ; Negatge the number | |
| ADDI 270 ; theta' = 270 - theta | |
| RETURN | |
| A2_R2: ; region 2 | |
| CALL A2_calc ; Octants 2, 3 | |
| CALL Neg ; negate the angle | |
| ADDI 90 ; theta' = 90 - theta | |
| RETURN | |
| A2_calc: | |
| ; calculates R/(1 + 0.28125*R^2) | |
| LOAD AtanY | |
| STORE d16sN ; Y in numerator | |
| LOAD AtanX | |
| STORE d16sD ; X in denominator | |
| CALL A2_div ; divide | |
| LOAD dres16sQ ; get the quotient (remainder ignored) | |
| STORE AtanRatio | |
| STORE m16sA | |
| STORE m16sB | |
| CALL A2_mult ; X^2 | |
| STORE m16sA | |
| LOAD A2c | |
| STORE m16sB | |
| CALL A2_mult | |
| ADDI 256 ; 256/256+0.28125X^2 | |
| STORE d16sD | |
| LOAD AtanRatio | |
| STORE d16sN ; Ratio in numerator | |
| CALL A2_div ; divide | |
| LOAD dres16sQ ; get the quotient (remainder ignored) | |
| STORE m16sA ; <= result in radians | |
| LOAD A2cd ; degree conversion factor | |
| STORE m16sB | |
| CALL A2_mult ; convert to degrees | |
| STORE AtanT | |
| SHIFT -7 ; check 7th bit | |
| AND One | |
| JZERO A2_rdwn ; round down | |
| LOAD AtanT | |
| SHIFT -8 | |
| ADDI 1 ; round up | |
| RETURN | |
| A2_rdwn: | |
| LOAD AtanT | |
| SHIFT -8 ; round down | |
| RETURN | |
| A2_mult: ; multiply, and return bits 23..8 of result | |
| CALL Mult16s | |
| LOAD mres16sH | |
| SHIFT 8 ; move high word of result up 8 bits | |
| STORE mres16sH | |
| LOAD mres16sL | |
| SHIFT -8 ; move low word of result down 8 bits | |
| AND LowByte | |
| OR mres16sH ; combine high and low words of result | |
| RETURN | |
| A2_div: ; 16-bit division scaled by 256, minimizing error | |
| LOADI 9 ; loop 8 times (256 = 2^8) | |
| STORE AtanT | |
| A2_DL: | |
| LOAD AtanT | |
| ADDI -1 | |
| JPOS A2_DN ; not done; continue shifting | |
| CALL Div16s ; do the standard division | |
| RETURN | |
| A2_DN: | |
| STORE AtanT | |
| LOAD d16sN ; start by trying to scale the numerator | |
| SHIFT 1 | |
| XOR d16sN ; if the sign changed, | |
| JNEG A2_DD ; switch to scaling the denominator | |
| XOR d16sN ; get back shifted version | |
| STORE d16sN | |
| JUMP A2_DL | |
| A2_DD: | |
| LOAD d16sD | |
| SHIFT -1 ; have to scale denominator | |
| STORE d16sD | |
| JUMP A2_DL | |
| AtanX: DW 0 | |
| AtanY: DW 0 | |
| AtanRatio: DW 0 ; =y/x | |
| AtanT: DW 0 ; temporary value | |
| A2c: DW 72 ; 72/256=0.28125, with 8 fractional bits | |
| A2cd: DW 14668 ; = 180/pi with 8 fractional bits | |
| ;******************************************************************************* | |
| ; Mult16s: 16x16 -> 32-bit signed multiplication | |
| ; Based on Booth's algorithm. | |
| ; Written by Kevin Johnson. No licence or copyright applied. | |
| ; Warning: does not work with factor B = -32768 (most-negative number). | |
| ; To use: | |
| ; - Store factors in m16sA and m16sB. | |
| ; - Call Mult16s | |
| ; - Result is stored in mres16sH and mres16sL (high and low words). | |
| ;******************************************************************************* | |
| Mult16s: | |
| LOADI 0 | |
| STORE m16sc ; clear carry | |
| STORE mres16sH ; clear result | |
| LOADI 16 ; load 16 to counter | |
| Mult16s_loop: | |
| STORE mcnt16s | |
| LOAD m16sc ; check the carry (from previous iteration) | |
| JZERO Mult16s_noc ; if no carry, move on | |
| LOAD mres16sH ; if a carry, | |
| ADD m16sA ; add multiplicand to result H | |
| STORE mres16sH | |
| Mult16s_noc: ; no carry | |
| LOAD m16sB | |
| AND One ; check bit 0 of multiplier | |
| STORE m16sc ; save as next carry | |
| JZERO Mult16s_sh ; if no carry, move on to shift | |
| LOAD mres16sH ; if bit 0 set, | |
| SUB m16sA ; subtract multiplicand from result H | |
| STORE mres16sH | |
| Mult16s_sh: | |
| LOAD m16sB | |
| SHIFT -1 ; shift result L >>1 | |
| AND c7FFF ; clear msb | |
| STORE m16sB | |
| LOAD mres16sH ; load result H | |
| SHIFT 15 ; move lsb to msb | |
| OR m16sB | |
| STORE m16sB ; result L now includes carry out from H | |
| LOAD mres16sH | |
| SHIFT -1 | |
| STORE mres16sH ; shift result H >>1 | |
| LOAD mcnt16s | |
| ADDI -1 ; check counter | |
| JPOS Mult16s_loop ; need to iterate 16 times | |
| LOAD m16sB | |
| STORE mres16sL ; multiplier and result L shared a word | |
| RETURN ; Done | |
| c7FFF: DW &H7FFF | |
| m16sA: DW 0 ; multiplicand | |
| m16sB: DW 0 ; multipler | |
| m16sc: DW 0 ; carry | |
| mcnt16s: DW 0 ; counter | |
| mres16sL: DW 0 ; result low | |
| mres16sH: DW 0 ; result high | |
| ;******************************************************************************* | |
| ; Div16s: 16/16 -> 16 R16 signed division | |
| ; Written by Kevin Johnson. No licence or copyright applied. | |
| ; Warning: results undefined if denominator = 0. | |
| ; To use: | |
| ; - Store numerator in d16sN and denominator in d16sD. | |
| ; - Call Div16s | |
| ; - Result is stored in dres16sQ and dres16sR (quotient and remainder). | |
| ; Requires Abs subroutine | |
| ;******************************************************************************* | |
| Div16s: | |
| LOADI 0 | |
| STORE dres16sR ; clear remainder result | |
| STORE d16sC1 ; clear carry | |
| LOAD d16sN | |
| XOR d16sD | |
| STORE d16sS ; sign determination = N XOR D | |
| LOADI 17 | |
| STORE d16sT ; preload counter with 17 (16+1) | |
| LOAD d16sD | |
| CALL Abs ; take absolute value of denominator | |
| STORE d16sD | |
| LOAD d16sN | |
| CALL Abs ; take absolute value of numerator | |
| STORE d16sN | |
| Div16s_loop: | |
| LOAD d16sN | |
| SHIFT -15 ; get msb | |
| AND One ; only msb (because shift is arithmetic) | |
| STORE d16sC2 ; store as carry | |
| LOAD d16sN | |
| SHIFT 1 ; shift <<1 | |
| OR d16sC1 ; with carry | |
| STORE d16sN | |
| LOAD d16sT | |
| ADDI -1 ; decrement counter | |
| JZERO Div16s_sign ; if finished looping, finalize result | |
| STORE d16sT | |
| LOAD dres16sR | |
| SHIFT 1 ; shift remainder | |
| OR d16sC2 ; with carry from other shift | |
| SUB d16sD ; subtract denominator from remainder | |
| JNEG Div16s_add ; if negative, need to add it back | |
| STORE dres16sR | |
| LOADI 1 | |
| STORE d16sC1 ; set carry | |
| JUMP Div16s_loop | |
| Div16s_add: | |
| ADD d16sD ; add denominator back in | |
| STORE dres16sR | |
| LOADI 0 | |
| STORE d16sC1 ; clear carry | |
| JUMP Div16s_loop | |
| Div16s_sign: | |
| LOAD d16sN | |
| STORE dres16sQ ; numerator was used to hold quotient result | |
| LOAD d16sS ; check the sign indicator | |
| JNEG Div16s_neg | |
| RETURN | |
| Div16s_neg: | |
| LOAD dres16sQ ; need to negate the result | |
| CALL Neg | |
| STORE dres16sQ | |
| RETURN | |
| d16sN: DW 0 ; numerator | |
| d16sD: DW 0 ; denominator | |
| d16sS: DW 0 ; sign value | |
| d16sT: DW 0 ; temp counter | |
| d16sC1: DW 0 ; carry value | |
| d16sC2: DW 0 ; carry value | |
| dres16sQ: DW 0 ; quotient result | |
| dres16sR: DW 0 ; remainder result | |
| ;******************************************************************************* | |
| ; L2Estimate: Pythagorean distance estimation | |
| ; Written by Kevin Johnson. No license or copyright applied. | |
| ; Warning: this is *not* an exact function. I think it's most wrong | |
| ; on the axes, and maybe at 45 degrees. | |
| ; To use: | |
| ; - Store X and Y offset in L2X and L2Y. | |
| ; - Call L2Estimate | |
| ; - Result is returned in AC. | |
| ; Result will be in same units as inputs. | |
| ; Requires Abs and Mult16s subroutines. | |
| ;******************************************************************************* | |
| L2Estimate: | |
| ; take abs() of each value, and find the largest one | |
| LOAD L2X | |
| CALL Abs | |
| STORE L2T1 | |
| LOAD L2Y | |
| CALL Abs | |
| SUB L2T1 | |
| JNEG GDSwap ; swap if needed to get largest value in X | |
| ADD L2T1 | |
| CalcDist: | |
| ; Calculation is max(X,Y)*0.961+min(X,Y)*0.406 | |
| STORE m16sa | |
| LOADI 246 ; max * 246 | |
| STORE m16sB | |
| CALL Mult16s | |
| LOAD mres16sH | |
| SHIFT 8 | |
| STORE L2T2 | |
| LOAD mres16sL | |
| SHIFT -8 ; / 256 | |
| AND LowByte | |
| OR L2T2 | |
| STORE L2T3 | |
| LOAD L2T1 | |
| STORE m16sa | |
| LOADI 104 ; min * 104 | |
| STORE m16sB | |
| CALL Mult16s | |
| LOAD mres16sH | |
| SHIFT 8 | |
| STORE L2T2 | |
| LOAD mres16sL | |
| SHIFT -8 ; / 256 | |
| AND LowByte | |
| OR L2T2 | |
| ADD L2T3 ; sum | |
| RETURN | |
| GDSwap: ; swaps the incoming X and Y | |
| ADD L2T1 | |
| STORE L2T2 | |
| LOAD L2T1 | |
| STORE L2T3 | |
| LOAD L2T2 | |
| STORE L2T1 | |
| LOAD L2T3 | |
| JUMP CalcDist | |
| L2X: DW 0 | |
| L2Y: DW 0 | |
| L2T1: DW 0 | |
| L2T2: DW 0 | |
| L2T3: DW 0 | |
| ; Subroutine to wait (block) for 1 second | |
| Wait1: | |
| OUT TIMER | |
| Wloop: | |
| IN TIMER | |
| OUT XLEDS ; User-feedback that a pause is occurring. | |
| ADDI -10 ; 1 second at 10Hz. | |
| JNEG Wloop | |
| RETURN | |
| ;*************************************************************** | |
| ;* Variables | |
| ;*************************************************************** | |
| Temp: DW 0 ; "Temp" is not a great name, but can be useful | |
| ;*************************************************************** | |
| ;* Constants | |
| ;* (though there is nothing stopping you from writing to these) | |
| ;*************************************************************** | |
| NegOne: DW -1 | |
| Zero: DW 0 | |
| One: DW 1 | |
| Two: DW 2 | |
| Three: DW 3 | |
| Four: DW 4 | |
| Five: DW 5 | |
| Six: DW 6 | |
| Seven: DW 7 | |
| Eight: DW 8 | |
| Nine: DW 9 | |
| Ten: DW 10 | |
| ; Some bit masks. | |
| ; Masks of multiple bits can be constructed by ORing these | |
| ; 1-bit masks together. | |
| Mask0: DW &B00000001 | |
| Mask1: DW &B00000010 | |
| Mask2: DW &B00000100 | |
| Mask3: DW &B00001000 | |
| Mask4: DW &B00010000 | |
| Mask5: DW &B00100000 | |
| Mask6: DW &B01000000 | |
| Mask7: DW &B10000000 | |
| LowByte: DW &HFF ; binary 00000000 1111111 | |
| LowNibl: DW &HF ; 0000 0000 0000 1111 | |
| ; some useful movement values | |
| OneMeter: DW 961 ; ~1m in 1.04mm units | |
| HalfMeter: DW 481 ; ~0.5m in 1.04mm units | |
| Ft2: DW 586 ; ~2ft in 1.04mm units | |
| Ft3: DW 879 | |
| Ft4: DW 1172 | |
| Deg90: DW 90 ; 90 degrees in odometer units | |
| Deg180: DW 180 ; 180 | |
| Deg270: DW 270 ; 270 | |
| Deg360: DW 360 ; can never actually happen; for math only | |
| FSlow: DW 100 ; 100 is about the lowest velocity value that will move | |
| RSlow: DW -100 | |
| FMid: DW 350 ; 350 is a medium speed | |
| RMid: DW -350 | |
| FFast: DW 500 ; 500 is almost max speed (511 is max) | |
| RFast: DW -500 | |
| MinBatt: DW 140 ; 14.0V - minimum safe battery voltage | |
| I2CWCmd: DW &H1190 ; write one i2c byte, read one byte, addr 0x90 | |
| I2CRCmd: DW &H0190 ; write nothing, read one byte, addr 0x90 | |
| DataArray: | |
| DW 0 | |
| ;*************************************************************** | |
| ;* IO address space map | |
| ;*************************************************************** | |
| SWITCHES: EQU &H00 ; slide switches | |
| LEDS: EQU &H01 ; red LEDs | |
| TIMER: EQU &H02 ; timer, usually running at 10 Hz | |
| XIO: EQU &H03 ; pushbuttons and some misc. inputs | |
| SSEG1: EQU &H04 ; seven-segment display (4-digits only) | |
| SSEG2: EQU &H05 ; seven-segment display (4-digits only) | |
| LCD: EQU &H06 ; primitive 4-digit LCD display | |
| XLEDS: EQU &H07 ; Green LEDs (and Red LED16+17) | |
| BEEP: EQU &H0A ; Control the beep | |
| CTIMER: EQU &H0C ; Configurable timer for interrupts | |
| LPOS: EQU &H80 ; left wheel encoder position (read only) | |
| LVEL: EQU &H82 ; current left wheel velocity (read only) | |
| LVELCMD: EQU &H83 ; left wheel velocity command (write only) | |
| RPOS: EQU &H88 ; same values for right wheel... | |
| RVEL: EQU &H8A ; ... | |
| RVELCMD: EQU &H8B ; ... | |
| I2C_CMD: EQU &H90 ; I2C module's CMD register, | |
| I2C_DATA: EQU &H91 ; ... DATA register, | |
| I2C_RDY: EQU &H92 ; ... and BUSY register | |
| UART_DAT: EQU &H98 ; UART data | |
| UART_RDY: EQU &H99 ; UART status | |
| SONAR: EQU &HA0 ; base address for more than 16 registers.... | |
| DIST0: EQU &HA8 ; the eight sonar distance readings | |
| DIST1: EQU &HA9 ; ... | |
| DIST2: EQU &HAA ; ... | |
| DIST3: EQU &HAB ; ... | |
| DIST4: EQU &HAC ; ... | |
| DIST5: EQU &HAD ; ... | |
| DIST6: EQU &HAE ; ... | |
| DIST7: EQU &HAF ; ... | |
| SONALARM: EQU &HB0 ; Write alarm distance; read alarm register | |
| SONARINT: EQU &HB1 ; Write mask for sonar interrupts | |
| SONAREN: EQU &HB2 ; register to control which sonars are enabled | |
| XPOS: EQU &HC0 ; Current X-position (read only) | |
| YPOS: EQU &HC1 ; Y-position | |
| THETA: EQU &HC2 ; Current rotational position of robot (0-359) | |
| RESETPOS: EQU &HC3 ; write anything here to reset odometry to 0 | |
| RIN: EQU &HC8 | |
| LIN: EQU &HC9 | |
| IR_HI: EQU &HD0 ; read the high word of the IR receiver (OUT will clear both words) | |
| IR_LO: EQU &HD1 ; read the low word of the IR receiver (OUT will clear both words) | |
| SRAM_CTRL: EQU &H10 ; write the two bits controlling SRAM function (bit 1 is write, bit 0 is output enable) | |
| SRAM_DATA: EQU &H11 ; write the data to go to SRAM (before setting control bits) or read the data from SRAM (after setting bits) | |
| SRAM_ADLOW: EQU &H12 ; write the lower 16 bits of the SRAM address (before setting control bits) | |
| SRAM_ADHI: EQU &H13 ; write the upper 2 bits of the SRAM address (before setting control bits) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment