$MOD151 ;************************************************************ ;* Mobile Robot Monitor Vsn 3.4 for Intel 87C151SA * ;* including user-accessible maths subroutines * ;* WGM 2000 Vsn 3.4 * ;* Code compatible with Intel 87C51FA devices * ;* Serial Communication setting: 19200,n,8,1 * ;* Use terminal emulator, e.g. Windows 'Terminal' * ;************************************************************ ; Monitor operates transparently via the serial port interrupt. ; Incoming hex digits get shifted into MPARAM. Any valid ; non-hex digit is interpreted as a command. ; The following commands are implemented here: ; R = Dump 8 registers, starting at specified register. ; X = Examine specified register continuously. ; S = Store data in specified register. ; M = Dump external memory, starting at specified location. ; N = Single-Step (Uses External Interrupt 0) ; W = Clear User RAM area ; J = Jump to program at specified location in User RAM. ; G = Run program in User RAM starting at 8012H. ; T = Run Motor Drive Test Programs ; Q = Reset Monitor ; Intel-HEX format is assumed for user program file downloads. No ; command necessary, just use 'Send Text File' from ; terminal emulator. ; Timer 1 used as baud rate clock. Assumes 11.0592 MHz Crystal. ; RAM Size and Location ; 32kbytes starting at 8000H for Micromouse 2000 board USER_RAM EQU 8000H ; Start of External RAM USER_SIZE EQU 8000H ; External RAM size DSEG ORG 0 ; These locations are only used by the Motor Drive Test programs RHV: DS 1 ; RH Tacho value H RLV: DS 1 ; RH Tacho value L LHV: DS 1 ; LH Tacho value H LLV: DS 1 ; LH Tacho value L RS: DS 1 ; RH set speed LS: DS 1 ; LH set speed RTMPH: DS 1 RTMPL: DS 1 LTMPH: DS 1 LTMPL: DS 1 RCNT: DS 1 LCNT: DS 1 LDIST: DS 1 RDIST: DS 1 SQ: DS 1 RSQCNT: DS 1 LSQCNT: DS 1 TESTNO: DS 1 ORG 18H ; Monitor reserves Register Bank 3 (18 to 1F) MPARAM: DS 2 ; Mem/Reg Pointer (r0,r1) MADDR: DS 2 ; (r2,r3) MI: DS 2 ; (r4,r5) MBYTES: DS 1 ; (r6) MINTEL: DS 1 ; Hex loader state (r7) ; Stack begins at 30H, builds upwards ; Monitor reserves Internal RAM 79 to 7F (Single-Step mode only) ORG 79H N1: DS 7 BSEG ; Monitor reserves Flag F0 and Bit 20H (TXRDY) ORG 0 TXRDY: DBIT 1 ; Serial port Tx ready flag IFLGR: DBIT 1 ; Only used by Drive Tests IFLGL: DBIT 1 ; Only used by Drive Tests LSTP: DBIT 1 ; Only used by Drive Tests RSTP: DBIT 1 ; Only used by Drive Tests CSEG ORG 0 ; System reset and interrupt vectors RST: ajmp Reset ; Reset Vector ORG 03H EXI0: ljmp USER_RAM ; INT0 interrupt vector ORG 0BH T0I: ljmp USER_RAM+3 ; Timer 0 interrupt vector ORG 13H EXI1: ljmp USER_RAM+6 ; INT1 interrupt vector ORG 1BH T1I: ljmp USER_RAM+9 ; Timer 1 interrupt vector ORG 23H SERI: jbc RI, SIsvc ; Serial In interrupt? jbc TI, SOsvc ; Serial Out ready? reti ORG 2BH T2I: ljmp USER_RAM+12 ; Timer 2 interrupt vector ORG 33H PCAI: ljmp USER_RAM+15 ; PCA interrupt vector ORG 36H Reset: mov IE, #0 ; Disable all interrupts mov IPL0, #10H ; Set Serial Interrupt Priority mov IPH0, #00H ; to Level 1 mov PSW, #00H ; Switch to Register Bank 0 mov TMOD, #20H ; Timer 1 is Baud Rate clock mov TH1, #0FDH ; Set baud rate: 9600 mov PCON, #80H ; Set 2 x Baud rate (19200) mov SP, #2FH ; Initialize stack pointer mov P1, #0FFH ; Initialize Port 1 mov P3, #0FFH ; Initialize Port 3 mov SCON, #50H ; Initialize serial port mov TCON, #40H ; Enable Timer 1 clr RI ; Clear serial input int flag clr TI ; Clear serial output int flag setb ES ; Unmask serial interrupt setb EA ; Enable global interrupt mov SBUF, #7 ; Ring Bell mov DPTR, #Hello acall SOstring ; Send sign-on message ; Monitor Main Base-Level Program Loop Main: orl PCON, #01H ; Enter Idle (low power) mode sjmp Main ; wait for serial port interrupt ; Serial Output Interrupt Service Routine SOsvc: setb TXRDY ; Set Tx Ready Flag reti ; Serial Input Interrupt Service Routine SIsvc: mov IPL0, #00H ; Set Serial Interrupt Priority mov IPH0, #10H ; to Level 2 push PSW ; Save processor status push ACC push B push dpl push dph orl PSW, #18H ; Switch to register bank 3 mov A, SBUF ; Get serial input character anl A, #7FH ; 7-bit ASCII characters only mov r4, A ; r4 = character add A, #133 jc SIX ; invalid if > z add A, #27 jnc SItst ; if a <= ch <= z mov A, r4 ; then add A, #224 ; convert to upper case mov r4, A SItst: mov A, r4 add A, #198 jz SIcolon ; If ':' then enable load add A, #10 ; a = ord(ch) - 48 jb acc.7, SIX ; ch < '0' add A, #246 jnc SInum ; '0' <= ch <= '9' add A, #249 ; a = a - 7 jnc SIX ; ch < 'A' SInum: add A, #10 ; a = hex digit 0..9, A..Z mov r4, A swap A anl A, #3 ; upper nibble: jz SIdigit add A, #253 jc SIX ; > _ mov r7, #0 ; stop download mov A, r4 add A, #240 ; A = 00 -> 1F push acc add A, #71 acall SO ; Echo command pop acc add A, acc ; A = A x 2 mov DPTR, #SItable ; point to command table jmp @A+DPTR ; obey command SIXe: acall SIPrmpt sjmp SIexit SIX: mov r7, #0 ; stop download SIexit: pop dph pop dpl pop B pop ACC pop PSW mov IPL0, #10H ; Reset Serial Interrupt Priority mov IPH0, #00H ; to Level 1 reti SIdigit: mov A, r7 ; Hex digit detected jnz SIintel ; Intel-HEX file download? mov A, SBUF ; No acall SO ; Echo typed hex characters call SIpush sjmp SIexit SIpush: mov A, r0 ; r0r1 = abcd swap A anl A, #0F0H ; b0 mov r5, A mov A, r1 swap A anl A, #0FH ; 0c orl A, r5 mov r0, A ; r0 = bc mov A, r1 swap A anl A, #0F0H ; d0 add A, r4 mov r1, A ; r1 = cd ret SIcolon: mov MINTEL, #72 ; Enable Intel-HEX loader sjmp SIexit ; Intel-HEX File Loader SIintel: djnz MINTEL, Siimore sjmp SIX Siimore: acall SIpush ; save incoming digit mov A, MINTEL ; decide what to do with it. jnb acc.6, SiiData ; MINTEL < 64: incoming data add A, #186 jz SiiNumbytes ; MINTEL = 70: no of bytes add A, #4 jz SiiAddr ; MINTEL = 66: set address add A, #2 jnz SIexit ; MINTEL = 64: skip zeros mov A, r6 inc A add A, acc mov MINTEL, A ; MINTEL = 2 * bytecount + 2 sjmp SIexit SiiAddr: mov A, r0 mov r2, A mov A, r1 mov r3, A sjmp SIexit SiiNumbytes: mov A, r1 mov r6, A sjmp SIexit SiiData: jb acc.0, SIExit ; If even byte then mov dph, r2 mov dpl, r3 mov A, r1 movx @DPTR, A ; Store data at address inc DPTR ; inc address pointer mov r2, dph mov r3, dpl sjmp SIexit ; Command Table SItable: ajmp SIGo ; G Go to program at 8012H ajmp SIX ; H ajmp SIX ; I ajmp SIjmp ; J Go to specified location ajmp SIX ; K ajmp SIX ; L ajmp SIMdump ; M External Memory Dump ajmp SINext ; N Next (single) step ajmp SIX ; O ajmp SIX ; P ajmp SIQuit ; Q Reset monitor ajmp SIRdump ; R Internal Register Dump ajmp SIstore ; S Modify Register ajmp SITest ; T Drive Test Programs ajmp SIX ; U ajmp SIX ; V ajmp SIWipe ; W Wipe (Clear) User RAM ajmp SIXam ; X Read Register continuously ajmp SIX ; Y ajmp SIX ; Z ajmp SIX ajmp SIX ajmp SIX ajmp SIX ajmp SIX ajmp SIX ajmp SIX ajmp SIX ajmp SIX ajmp SIX ajmp SIX ajmp SIX ; Command: M(emory) ; Dump external memory from (MPARAM) onwards SIMdump: mov dph, MPARAM ; dph = MPARAM mov A, MPARAM+1 anl A, #0F0H ; start at xxx0 mov MPARAM+1, A mov dpl, A acall CRLF mov A, dph ; Print address acall sbyte mov A, dpl acall sbyte acall space ; Print 2 spaces acall space SIMloop0: movx A, @DPTR ; Print 16 bytes acall sbyte acall space inc DPTR mov A, dpl anl A, #0FH jnz SIMloop0 mov dph, MPARAM ; Restore DPTR mov dpl, MPARAM+1 acall space SIMloop1: movx A, @DPTR ; Now print as ASCII inc DPTR mov MI+1, A add A, #129 jc SIMdot ; ch > 127 ?, print '.' add A, #95 jc SIMch ; ch > 31 ?, print '.' SIMdot: mov MI+1, #46 SIMch: mov A, MI+1 ; Print character acall SO mov A, dpl anl A, #0FH jnz SIMloop1 mov MPARAM, dph mov MPARAM+1, dpl ajmp SIXe ; Command: R(egister) ; Internal register dump SIRdump: acall CRLF mov A, r1 acall sbyte ; Print reg address acall space mov A, #'=' ; Print '=' acall SO acall space SIRloop: mov A, @r1 ; Print reg contents acall sbyte acall space inc r1 mov A, r1 anl A, #7 jnz SIRloop ajmp SIXe ; Command:S(tore) ; Modify Internal Register SIstore: mov A, r1 ; Get data mov @r0, A ; Store data mov A, r0 ; Inc register address inc A mov r1, A ajmp SIXe ; Command: J(ump) ; Jump to specified location SIjmp: acall SIPrmpt pop dph pop dpl pop B pop ACC pop PSW dec SP ; Scrap old return address dec SP push MPARAM+1 ; Push new return address push MPARAM acall rstint ; Reset Interrupt system mov IPL0, #10H ; Reset Serial Interrupt Priority mov IPH0, #00H ; to Level 1 rstint: reti ; Command: G(o) ; Run program at location USER_RAM+12H SIGo: mov MPARAM, #(USER_RAM/256) mov MPARAM+1, #12H sjmp SIjmp ; Command: Q(uit) ; Force MouseMon Soft Reset SIQuit: mov MPARAM, #(Reset/256) mov MPARAM+1, #(Reset MOD 256) sjmp SIjmp ; Command: (W)ipe Memory ; Clears User RAM area SIWipe: mov DPTR, #USER_RAM SIW: clr A movx @DPTR, A inc DPTR mov A, dph cjne A, #((USER_RAM+USER_SIZE)/256), SIW ajmp SIXe ; Command: (N)ext Step ; Single-Step through User program SINext: acall SIPrmpt mov DPTR, #Step ; Change INT0 Interrupt Vector push dpl ; in RAM to point to 'Step'. push dph mov DPTR, #USER_RAM mov A, #02H ; Op code for LJMP movx @DPTR, A inc DPTR pop ACC movx @DPTR, A inc DPTR pop ACC movx @DPTR, A mov IPL0, #10H ; Reset Serial Interrupt Priority mov IPH0, #00H ; to Level 1 setb EX0 ; Enable Step Interrupt (INT0) pop dph pop dpl pop B pop ACC pop PSW setb F0 ; Set Step Flag clr P3.2 ; Force Ext Interrupt 0 reti ; Command: e(X)amine ; Dump contents of the specified register continuously SIXam: acall CRLF ; Print Newline mov DPTR, #Exam ; Change INT0 Interrupt Vector push dpl ; in RAM to point to 'Exam'. push dph mov DPTR, #USER_RAM mov A, #02H ; Op code for LJMP movx @DPTR, A inc DPTR pop ACC movx @DPTR, A inc DPTR pop ACC movx @DPTR, A mov IPL0, #10H ; Reset Serial Interrupt Priority mov IPH0, #00H ; to Level 1 setb EX0 ; Enable Step Interrupt (INT0) pop dph pop dpl pop B pop ACC pop PSW clr P3.2 ; Force Ext Interrupt 0 reti ; Built-In Motor Drive Test Programs ; Port 1 used for motor drive and tacho feedback. ; Motor board links in position 'X' ; P1.0 = Left motor A output ; P1.1 = Left motor B output ; P1.2 = Right motor A output ; P1.3 = Right motor B output ; P1.4 = Left motor Enable/PWM output ; P1.5 = Right motor Enable/PWM output ; P1.6 = Left motor Tacho input ; P1.7 = Right motor Tacho input ; P1 = 11110101 Forwards ; P1 = 11111010 Backwards ; P1 = 11000000 Stop SITest: mov RS, MPARAM+1 ; Get selected speed mov LS, MPARAM+1 mov TESTNO, MPARAM ; Get Test No. mov MPARAM, #(tprog/256) mov MPARAM+1, #(tprog MOD 256) ajmp SIjmp ; Exit to test program tprog: mov DPTR, #TachI ; Set up PCA Interrupt Vector push dpl ; in RAM to point to 'TachI'. push dph mov DPTR, #USER_RAM+15 mov A, #02H ; Op code for LJMP movx @DPTR, A inc DPTR pop ACC movx @DPTR, A inc DPTR pop ACC movx @DPTR, A mov P3, #0FFH mov P1, #0C0H ; Disable motors anl PSW, #0E7H ; Select Reg bank 0 clr EC ; Disable PCA interrupt clr CR ; Disable PCA timer mov CL, #00H ; Clear PCA timer (low) mov CH, #00H ; Clear PCA timer (high) mov CMOD, #00H ; PCA Timer Clock = Osc/12 mov CCAPM1, #42H ; PWM mode, LH motor mov CCAPM2, #42H ; PWM mode, RH motor mov CCAPM3, #21H ; Positive edge, capture reg 3 mov CCAPM4, #21H ; Positive edge, capture reg 4 mov RCNT, #4 ; Capture 4 Right Tacho cycles mov LCNT, #4 ; Capture 4 Left Tacho cycles clr IFLGR clr IFLGL setb EA ; Enable Global Interrupt mov CCAP1H, #00 ; Set start at full speed L mov CCAP2H, #00 ; Set start at full speed R ; Test 1 used to measure motor current at various speed settings ; off-load: micromouse 'jacked-up'. RHV, RLV and LHV, LLV contain ; the measured speed values. Use (Q)uit to exit. ; System run open-loop Test1: djnz TESTNO, Test2 ; Test 1 selected? setb CR ; Enable PCA timer mov P1, #0F5H ; Turn on motors mov r0, #2 ; Start at full speed mov r1, #0 mov r2, #0 lcall delay mov CCAP1H, LS ; Set speed L mov CCAP2H, RS ; Set speed R setb EC ; Enable PCA interrupt ; Main program loop Test 1 wall: sjmp wall ; Test 2 used to measure speed at various PWM settings, on-load ; Mouse moves about 3 feet and stops. RHV, RLV and LHV, LLV contain ; the last measured speed values. Test2: djnz TESTNO, Test3 ; Test 2 selected? mov SQ, #56 ; 1 square = 56 x 4 tacho pulses mov LDIST, #56 mov RDIST, #56 mov LSQCNT, #6 mov RSQCNT, #6 clr LSTP clr RSTP clr IFLGR clr IFLGL mov r0, #100 ; Wait a few seconds mov r1, #0 mov r2, #0 lcall delay setb EA ; Enable Global Interrupt setb CR ; Enable PCA timer mov P1, #0F5H ; Turn on motors at full mov r0, #4 ; speed for a bit... lcall delay mov CCAP1H, LS ; Set PWM L mov CCAP2H, RS ; Set PWM R setb EC ; Enable PCA interrupt ; Main program loop Test 2 wall1: jnb LSTP, sl ; Stop L? anl P1, #0EFH mov CCAPM3, #00 ; Ignore further tacho pulses sl: jnb RSTP, wall1 ; Stop R? anl P1, #0DFH mov CCAPM4, #00 ; Ignore further tacho pulses sjmp wall1 ; Test 3 causes the mouse to move briefly at full speed, then ramp ; sharply to a stop. It is used to find the motor speed just before ; the gearbox 'locks up'. The last speed readings provide a measure ; of the deceleration at this point. Speed samples are logged in an ; array from 9000H onwards. Test3: djnz TESTNO, ramp1 ; Test 3 selected? mov TESTNO, #2 ; Set ramp rate mov DPTR, #9000H ; Base of data array clra: clr A ; Clear data array movx @DPTR, A inc DPTR mov A, dph cjne A, #93H, clra mov dph, #90H clr IFLGR clr IFLGL mov r0, #100 ; Wait a few seconds mov r1, #00 mov r2, #00 lcall delay setb CR ; Enable PCA timer setb EA ; Enable Global Interrupt mov P1, #0F5H ; Turn on motors mov r0, #4 ; Wait a bit... lcall delay setb EC ; Enable PCA interrupt ramp1: sjmp ramp1 ; PCA Interrupt Service Routine TachI: jbc CCF3, tachl ; Left tacho interrupt? jbc CCF4, tachr ; Right tacho interrupt? reti tachr: jb IFLGR, nxtr ; First edge capture? setb IFLGR ; Yes mov RTMPL, CCAP4L mov RTMPH, CCAP4H sjmp TachI nxtr: djnz RCNT, TachI ; Last edge capture? mov RCNT, #4 ; Yes clr IFLGR ; Set first edge capture clr C mov A, CCAP4L ; Find change in timer count subb A, RTMPL mov RLV, A mov A, CCAP4H subb A, RTMPH mov RHV, A mov A, TESTNO cjne A, #2, skp1 ; Is this Test 3 ? mov A, RHV ; Yes, save data in array movx @DPTR, A inc DPTR mov A, RLV movx @DPTR, A inc DPTR skp1: mov A, CCAP2H ; Ramp R speed (if selected) add A, TESTNO mov CCAP2H, A mov A, CCAP1H ; Ramp L speed (if selected) add A, TESTNO mov CCAP1H, A djnz RDIST, TachI mov RDIST, SQ djnz RSQCNT, TachI ; Moved desired distance? setb RSTP ; Yes sjmp TachI tachl: jb IFLGL, nxtl ; First edge capture? setb IFLGl ; Yes mov LTMPL, CCAP3L mov LTMPH, CCAP3H sjmp TachI nxtl: djnz LCNT, TachI ; Last edge capture? mov LCNT, #4 ; Yes clr IFLGL ; Set first edge capture clr C mov A, CCAP3L ; Find change in timer count subb A, LTMPL mov LLV, A mov A, CCAP3H subb A, LTMPH mov LHV, A djnz LDIST, TachI mov LDIST, SQ djnz LSQCNT, TachI ; Moved desired distance? setb LSTP ; Yes sjmp TachI ; Print Command Prompt Routine SIPrmpt: acall CRLF mov A, #'>' ; Print '>' acall SO ret ; Print CR/LF Routine CRLF: mov A, #13 ; Send CR/LF acall SO mov A, #10 acall SO ret ; Print space character Routine Space: mov A, #' ' ; Print space acall SO ret ; Print character string Routine ; DPTR --> string SOstring: clr A movc A, @A+DPTR inc DPTR jz SOstrx ; 0 = terminate acall SO ; else print char sjmp SOstring SOstrx: ret ; Print Hex Byte Routine ; Byte is in Acc Sbyte: push ACC swap A acall Snibble pop ACC Snibble: anl A, #0FH ; Print hex nibble add A, #246 jnc Snibble0 add A, #7 Snibble0: add A, #58 ; Serial Output Routine ; ASCII Character is in Acc SO: jnb TXRDY, SO ; Transmitter ready? clr TXRDY mov SBUF, A ; Send character ret ; External INT0 (Single-Step) Service Routine Step: pop N1+6 ; Get next PCh pop N1+5 ; Get next PCl mov N1, PSW ; Save processor status mov N1+2, A ; Save acc clr C mov A, N1+6 ; Check to see if next step subb A, #20H ; is in external program RAM jc qexit ; Exit quickly if not clr F0 ; Clear Step flag mov N1+1, B ; Save B mov N1+3, dph ; Save dph mov N1+4, dpl ; Save dpl mov DPTR, #SSMsg acall SOstring ; Print Step header mov A, N1+2 acall Sbyte ; Print Acc acall Space acall Space mov A, N1+1 ; Print B acall Sbyte acall Space acall Space mov A, N1+3 ; Print DPTR acall Sbyte mov A, N1+4 acall Sbyte acall Space acall Space mov A, N1 ; Print PSW acall Sbyte acall Space acall Space acall Space mov A, P1 ; Print Port 1 acall Sbyte acall Space acall Space mov A, P3 ; Print Port 3 acall Sbyte acall Space acall Space mov A, SP ; Print Stack Pointer acall Sbyte acall Space acall Space mov A, N1+6 acall Sbyte ; Print next PCh mov A, N1+5 acall Sbyte ; Print next PCl acall SIprmpt jnb F0, $ ; Wait for Step command (N) mov dpl, N1+4 ; Restore registers mov dph, N1+3 mov B, N1+1 qexit: mov PSW, N1 mov A, N1+2 push N1+5 push N1+6 reti ; External INT0 (Examine) Service Routine Exam: push acc push PSW orl PSW, #18H ; Switch to Register Bank 3 mov A, @r1 ; Get specified register acall sbyte ; Print register contents mov A, #13 ; Print CR only acall SO pop PSW pop acc reti ; Messages Hello: DB 13,10,10,'Mobile Robot Monitor Vsn 3.4' DB 13,10,'(R)eg Dump e(X)amine (S)tore Reg ' DB '(M)em Dump',13,10,'(W)ipe Mem (N)ext (J)ump ' DB '(G)o User (T)est',13,10,'(Q)uit',13,10,10,'>',0 SSMsg: DB 'A B DPTR PSW P1 P3 SP Next',13,10,' ',0 ;***************************************************************** ;* * ;* Some Useful Subroutines * ;* * ;***************************************************************** ; All parameters in Register bank 0, (r0 to r7) ; Bits 21H and 22H reserved for sign bits ;================================================================= ; subroutine Cr0 ; 8-Bit 2's Complement -> magnitude / Sign Bit Conversion ; ; input: r0 = signed byte ; ; output: r0 = magnitude ; Bit 21H = sign (21H is set if r0 is a negative number) ; ; alters: acc ;================================================================= Cr0: mov a, r0 ; read X into accumulator jb acc.7, Cr0a ; X is negative if bit 7 is 1 clr 21H ; clear sign bit if 'positive' ret ; done Cr0a: cpl a ; X negative, find abs value inc a ; XA = complement(XT)+1 mov r0, a ; save magnitude setb 21H ; set sign bit if 'negative' ret ;================================================================= ; subroutine Cr1 ; 8-Bit 2's Complement -> magnitude / Sign Bit Conversion ; ; input: r1 = signed byte ; ; output: r1 = magnitude ; Bit 22H = sign (22H is set if r1 is a negative number) ; ; alters: acc ;================================================================= Cr1: mov a, r1 ; read X into accumulator jb acc.7, Cr1a ; X is negative if bit 7 is 1 clr 22H ; clear sign bit if 'positive' ret ; done Cr1a: cpl a ; X negative, find abs value inc a ; XA = complement(XT)+1 mov r1, a ; save magnitude setb 22H ; set sign bit if 'negative' ret ;=================================================================== ; subroutine Cr0r1 ; 16-Bit 2's Complement -> magnitude / Sign Bit Conversion ; ; input: r1, r0 = signed word ; ; output: r1, r0 = magnitude ; Bit 21H = sign (21H is set if negative number) ; ; alters: acc, C ;=================================================================== Cr0r1: mov a, r1 ; high byte into accumulator jb acc.7, c0a ; negative if bit 7 is 1 clr 21H ; clear sign bit if 'positive' ret ; done c0a: setb 21H ; set sign flag mov a, r0 ; number is negative cpl a ; complement add a, #1 ; and add +1 mov r0, a mov a, r1 ; get next byte cpl a ; complement addc a, #0 mov r1, a ret ;==================================================================== ; subroutine Cr2r3 ; 16-Bit 2's Complement -> magnitude / Sign Bit Conversion ; ; input: r3, r2 = signed word ; ; output: r3, r2 = magnitude ; Bit 22H = sign (22H is set if negative number) ; ; alters: acc, C ;==================================================================== Cr2r3: mov a, r3 ; read high into accumulator jb acc.7, c1a ; negative if bit 7 is 1 clr 22H ; clear sign bit if 'positive' ret ; done c1a: setb 22H ; set sign flag mov a, r2 ; number is negative cpl a ; complement add a, #1 ; and add +1 mov r2, a mov a, r3 ; get next byte cpl a ; complement addc a, #0 mov r3, a ret ;==================================================================== ; subroutine Cr4r5 ; 16-Bit 2's Complement -> magnitude / Sign Bit Conversion ; ; input: r5, r4 = signed word ; ; output: r5, r4 = magnitude ; Bit 21H = sign (21H is set if negative number) ; ; alters: acc, C ;==================================================================== Cr4r5: mov a, r5 ; read high into accumulator jb acc.7, c3a ; negative if bit 7 is 1 clr 21H ; clear sign bit if 'positive' ret ; done c3a: setb 21H ; set sign flag mov a, r4 ; number is negative cpl a ; complement add a, #1 ; and add +1 mov r4, a mov a, r5 ; get next byte cpl a ; complement addc a, #0 mov r5, a ret ;==================================================================== ; subroutine Cr0r3 ; 32-Bit 2's Complement -> magnitude / Sign Bit Conversion ; ; input: r3, r2, r1, r0 = signed word ; ; output: r3, r2, r1, r0 = magnitude ; Bit 21H = sign (21H is set if negative number) ; ; alters: acc ;==================================================================== Cr0r3: mov a, r3 ; read high into accumulator jb acc.7, c2a ; negative if bit 7 is 1 clr 21H ; clear sign flag if 'positive' ret ; done c2a: setb 21H ; set sign flag mov a, r0 ; number is negative cpl a ; complement add a, #1 ; and add +1 mov r0, a mov a, r1 ; get next byte cpl a ; complement addc a, #0 mov r1,a mov a, r2 ; get next byte cpl a ; complement addc a, #0 mov r2,a mov a, r3 ; get next byte cpl a ; complement addc a, #0 mov r3, a ret ; done ;================================================================== ; subroutine Mr0 ; 8-Bit magnitude / Sign Bit -> 2's Complement Conversion ; ; input: r0 = magnitude ; Bits 21H & 22H = sign bits of operands X and Y ; (set if negative) ; ; output: r0 = signed byte ; ; alters: acc ;================================================================== Mr0: jb 21H, Mr0b ; test X sign jb 22H, Mr0a ; test Y sign ret Mr0b: jnb 22H, Mr0a ret Mr0a: mov a, r0 ; if r0 negative, get abs value cpl a ; complement magnitude of X inc a ; r0 = complement(r0)+1 mov r0, a ; save in 2's complement ret ; done ;==================================================================== ; subroutine Mr0r1 ; 16-Bit magnitude / Sign Bit -> 2's Complement Conversion ; ; input: r1, r0 = magnitude ; Bits 21H & 22H = sign bits of operands X and Y ; (set if negative) ; ; output: r1, r0 = signed word ; ; alters: acc, C ;==================================================================== Mr0r1: jb 21H, Mr0r1b ; test X sign jb 22H, Mr0r1a ; test Y sign ret Mr0r1b: jnb 22H, Mr0r1a ret Mr0r1a: mov a, r0 ; negate number cpl a ; complement add a, #1 ; and add +1 mov r0, a mov a, r1 ; get next byte cpl a ; complement addc a, #0 mov r1, a ret ;==================================================================== ; subroutine Mr0r3 ; 32-Bit magnitude / Sign Bit -> 2's Complement Conversion ; ; input: r3, r2, r1, r0 = magnitude ; Bits 21H & 22H = sign bits of operands X and Y ; (set if negative) ; ; output: r3, r2, r1, r0 = signed word ; ; alters: acc, C ;==================================================================== Mr0r3: jb 21H, Mr0r3b ; test X sign jb 22H, Mr0r3a ; test Y sign ret Mr0r3b: jnb 22H, Mr0r3a ret Mr0r3a: mov a, r0 ; negate number cpl a ; complement add a, #1 ; and add +1 mov r0, a mov a, r1 ; get next byte cpl a ; complement addc a, #0 mov r1, a mov a, r2 ; get next byte cpl a ; complement addc a, #0 mov r2, a mov a, r3 ; get next byte cpl a ; complement addc a, #0 mov r3, a ret ; done ;==================================================================== ; subroutine ADD16 ; 16-Bit Signed (2's Complement) Addition ; ; input: r1, r0 = X ; r3, r2 = Y ; ; output: r1, r0 = signed sum S = X + Y ; Carry C is set if the result (S) is out of range ; ; alters: acc, C, OV ;==================================================================== ADD16: anl PSW, #0E7H ; Register Bank 0 mov a, r0 ; load X low byte into acc add a, r2 ; add Y low byte mov r0, a ; put result in Z low byte mov a, r1 ; load X high byte into acc addc a, r3 ; add Y high byte with carry mov r1, a ; save result in Z high byte mov C, OV ret ;==================================================================== ; subroutine ADD32 ; 32-Bit Signed (2's Complement) Addition ; ; input: r3, r2, r1, r0 = X ; r7, r6, r5, r4 = Y ; ; output: r3, r2, r1, r0 = signed sum S = X + Y ; Carry C is set if the result (S) is out of range ; ; alters: acc, C, OV ;==================================================================== ADD32: anl PSW, #0E7H ; Register Bank 0 mov a, r0 ; load X low byte into acc add a, r4 ; add Y low byte mov r0, a ; save result mov a, r1 ; load X next byte into acc addc a, r5 ; add Y next byte with carry mov r1, a ; save result mov a, r2 ; load X next byte into acc addc a, r6 ; add Y next byte mov r2, a ; save result mov a, r3 ; load X high byte into acc addc a, r7 ; add Y high byte with carry mov r3, a mov C, OV ret ;==================================================================== ; subroutine SUB16 ; 16-Bit Signed (2's Complement) Subtraction ; ; input: r1, r0 = X ; r3, r2 = Y ; ; output: r1, r0 = signed difference D = X - Y ; Carry C is set if the result (D) is out of range. ; ; alters: acc, C, OV ;==================================================================== SUB16: anl PSW, #0E7H ; Register Bank 0 mov a, r0 ; load X low byte into acc clr C ; clear carry flag subb a, r2 ; subract Y low byte mov r0, a ; put result in Z low byte mov a, r1 ; load X high into accumulator subb a, r3 ; subtract Y high with borrow mov r1, a ; save result in Z high byte mov C, OV ret ;==================================================================== ; subroutine SUB32 ; 32-Bit Signed (2's Complement) subtraction ; ; input: r3, r2, r1, r0 = X ; r7, r6, r5, r4 = Y ; ; output: r3, r2, r1, r0 = signed difference D = X - Y ; Carry C is set if the result (D) is out of range. ; ; alters: acc, C, OV ;==================================================================== SUB32: anl PSW, #0E7H ; Register Bank 0 mov a, r0 ; load X low byte into acc clr C ; clear carry flag subb a, r4 ; subract Y low byte mov r0, a ; put result in Z low byte mov a, r1 ; repeat with other bytes... subb a, r5 mov r1, a mov a, r2 subb a, r6 mov r2, a mov a, r3 subb a, r7 mov r3, a mov C, OV ; set C if external borrow ret ;================================================================== ; subroutine MUL8 ; 8-Bit x 8-Bit to 16-Bit Product Signed Multiply ; 2's Complement format ; ; input: r0 = multiplicand X ; r1 = multiplier Y ; ; output: r1, r0 = product P = X x Y. ; ; calls: UMUL8, Cr0, Cr1, Mr0r1 ; ; alters: acc, C, Bits 21H & 22H ;================================================================== MUL8: anl PSW, #0E7H ; Register Bank 0 acall Cr0 ; 2's comp -> Mag/Sign acall Cr1 ; 2's comp -> Mag/Sign acall UMUL8 acall Mr0r1 ; Mag/Sign -> 2's Comp ret ;================================================================== ; subroutine UMUL8 ; 8-Bit x 8-Bit to 16-Bit Product Unsigned Multiply ; ; input: r0 = multiplicand X ; r1 = multiplier Y ; ; output: r1, r0 = product P = X x Y. ; ; alters: acc ;================================================================== UMUL8: push b mov a, r0 ; read X and ... mov b, r1 ; ... Y mul ab ; multiply X and Y mov r1, b ; save result high ... mov r0, a ; ... and low pop b ret ;==================================================================== ; subroutine MUL816 ; 8-Bit x 16-Bit to 32-Bit Product signed Multiply ; 2's Complement format ; ; input: r0 = multiplicand X ; r3, r2 = multiplier Y ; ; output: r3, r2, r1, r0 = product P = X x Y (r3 = sign extension) ; ; calls: Cr0, Cr2r3, Mr0r3 ; ; alters: acc, C, Bits 21H & 22H ;==================================================================== MUL816: push b anl PSW, #0E7H ; Register Bank 0 acall Cr0 ; 2's comp -> Mag/Sign acall Cr2r3 ; 2's comp -> Mag/Sign mov a, r0 ; load X low byte into acc mov b, r2 ; load Y low byte into B mul ab ; multiply push acc ; stack result low byte push b ; stack result high byte mov a, r0 ; load X into acc again mov b, r3 ; load Y high byte into B mul ab ; multiply pop 00H ; recall X*YL high byte add a, r0 ; add X*YL high and X*YH low mov r1, a ; save result clr a ; clear accumulator addc a, b ; a = b + carry flag mov r2, a ; save result pop 00H ; get low result mov r3, #0 acall Mr0r3 ; Mag/Sign -> 2's Comp pop b ret ;==================================================================== ; subroutine MUL16 ; 16-Bit x 16-Bit to 32-Bit Product Signed Multiply ; 2's Complement format ; ; input: r1, r0 = multiplicand X ; r3, r2 = multiplier Y ; ; output: r3, r2, r1, r0 = product P = X x Y ; ; calls: UMUL16, Cr0r1, Cr2r3, Mr0r3 ; ; alters: acc, C, Bits 21H & 22H ;==================================================================== MUL16: anl PSW, #0E7H ; Register Bank 0 acall Cr0r1 ; 2's comp -> Mag/Sign acall Cr2r3 ; 2's comp -> Mag/Sign acall UMUL16 acall Mr0r3 ; Mag/Sign -> 2's Comp ret ;==================================================================== ; subroutine UMUL16 ; 16-Bit x 16-Bit to 32-Bit Product Unsigned Multiply ; ; input: r1, r0 = multiplicand X ; r3, r2 = multiplier Y ; ; output: r3, r2, r1, r0 = product P = X x Y ; ; alters: acc, C ;==================================================================== UMUL16: push B push dpl mov a, r0 mov b, r2 mul ab ; multiply XL x YL push acc ; stack result low byte push b ; stack result high byte mov a, r0 mov b, r3 mul ab ; multiply XL x YH pop 00H add a, r0 mov r0, a clr a addc a, b mov dpl, a mov a, r2 mov b, r1 mul ab ; multiply XH x YL add a, r0 mov r0, a mov a, dpl addc a, b mov dpl, a clr a addc a, #0 push acc ; save intermediate carry mov a, r3 mov b, r1 mul ab ; multiply XH x YH add a, dpl mov r2, a pop acc ; retrieve carry addc a, b mov r3, a mov r1, 00H pop 00H ; retrieve result low byte pop dpl pop B ret ;==================================================================== ; subroutine MAC16 ; 16-Bit x 16-Bit to 32-Bit Product signed Multiply-Accumulate ; 2's Complement format ; ; input: r1, r0 = multiplicand X ; r3, r2 = multiplier Y ; r7, r6, r5, r4 = 32-bit accumulator Ar ; ; output: r7, r6, r5, r4 = accumulated result Ar = Ar + (X x Y) ; r3, r2, r1, r0 = multiply result M = X x Y ; Carry C set if overflow ; ; calls: MUL16 ; ; alters: acc, C, Bits 21H & 22H ;==================================================================== MAC16: anl PSW, #0E7H ; Register Bank 0 acall MUL16+3 mov A, r4 add A, r0 mov r4, A mov A, r5 addc A, r1 mov r5, A mov A, r6 addc A, r2 mov r6, A mov A, r7 addc A, r3 mov r7, A mov C, OV ret ;=============================================================== ; subroutine DIV8 ; 8-Bit / 8-Bit to 8-Bit Quotient & Remainder signed Divide ; 2's Complement Format ; ; input: r0 = Dividend X ; r1 = Divisor Y ; ; output: r0 = quotient Q of division Q = X / Y ; r1 = remainder ; ; calls: Cr0, Cr1, Mr0 ; ; alters: acc, C, Bits 21H & 22H ;=============================================================== DIV8: anl PSW, #0E7H ; Register Bank 0 acall Cr0 ; 2's comp -> Mag/Sign acall Cr1 ; 2's comp -> Mag/Sign acall UDIV8 acall Mr0 ; Mag/Sign -> 2's Comp ret ;=============================================================== ; subroutine UDIV8 ; 8-Bit / 8-Bit to 8-Bit Quotient & Remainder Unsigned Divide ; ; input: r0 = Dividend X ; r1 = Divisor Y ; ; output: r0 = quotient Q of division Q = X / Y ; r1 = remainder ; ; ; alters: acc, C ;=============================================================== UDIV8: push b mov a, r0 ; read X and ... mov b, r1 ; ... Y div ab ; divide X and Y mov r0, a ; save result quotient mov r1, b ; save remainder pop b ret ;==================================================================== ; subroutine DIV16 ; 16-Bit / 16-Bit to 16-Bit Quotient & remainder signed Divide ; 2's Complement Format ; ; input: r1, r0 = Dividend X ; r3, r2 = Divisor Y ; ; output: r1, r0 = quotient Q of division Q = X / Y ; r3, r2 = remainder ; Carry C is set if Y = 0, i.e. divide by 0 attempted ; ; calls: UDIV16, Cr0r1, Cr2r3, Mr0r1 ; ; alters: acc, r4, r5, r6, r7, flags, Bits 21H & 22H ;==================================================================== DIV16: anl PSW, #0E7H ; Register Bank 0 mov a, r3 ; get divisor high byte orl a, r2 ; OR with low byte jnz div_OK ; divisor OK if not 0 setb C ; else, overflow ret div_OK: push dpl push dph push b acall Cr0r1 ; 2's comp -> Mag/Sign acall Cr2r3 ; 2's comp -> Mag/Sign acall UDIV16 acall Mr0r1 ; Mag/Sign -> 2's Comp clr C pop b pop dph pop dpl ret ; done ;==================================================================== ; subroutine UDIV16 ; 16-Bit / 16-Bit to 16-Bit Quotient & Remainder Unsigned Divide ; ; input: r1, r0 = Dividend X ; r3, r2 = Divisor Y ; ; output: r1, r0 = quotient Q of division Q = X / Y ; r3, r2 = remainder ; ; alters: acc, B, dpl, dph, r4, r5, r6, r7, flags ;==================================================================== UDIV16: mov r7, #0 ; clear partial remainder mov r6, #0 mov B, #16 ; set loop count div_loop: clr C ; clear carry flag mov a, r0 ; shift the highest bit of rlc a ; the dividend into... mov r0, a mov a, r1 rlc a mov r1, a mov a, r6 ; ... the lowest bit of the rlc a ; partial remainder mov r6, a mov a, r7 rlc a mov r7, a mov a, r6 ; trial subtract divisor clr C ; from partial remainder subb a, r2 mov dpl, a mov a, r7 subb a, r3 mov dph, a cpl C ; complement external borrow jnc div_1 ; update partial remainder if ; borrow mov r7, dph ; update partial remainder mov r6, dpl div_1: mov a, r4 ; shift result bit into partial rlc a ; quotient mov r4, a mov a, r5 rlc a mov r5, a djnz B, div_loop mov a, r5 ; put quotient in r0, and r1 mov r1, a mov a, r4 mov r0, a mov a, r7 ; get remainder, saved before the mov r3, a ; last subtraction mov a, r6 mov r2, a ret ;==================================================================== ; subroutine DIV32 ; 32-Bit / 16-Bit to 32-Bit Quotient & remainder signed Divide ; 2's Complement Format ; ; input: r3, r2, r1, r0 = Dividend X ; r5, r4 = Divisor Y ; ; output: r3, r2, r1, r0 = quotient Q of division Q = X / Y ; r7, r6, r5, r4 = remainder ; Carry C is set if Y = 0, i.e. divide by 0 attempted ; ; calls: UDIV32, Cr0r3, Cr4r5, Mr0r3 ; ; alters: acc, flags, Bits 21H & 22H ;==================================================================== DIV32: anl PSW, #0E7H ; Register Bank 0 mov a, r4 ; get divisor high byte orl a, r5 ; OR with low byte jnz div32_OK ; divisor OK if not 0 setb C ; else, overflow ret div32_OK: acall Cr0r3 ; 2's comp -> Mag/Sign acall Cr4r5 ; 2's comp -> Mag/Sign acall UDIV32 acall Mr0r3 ; Mag/Sign -> 2's Comp clr C ; divisor is not 0 ret ; done ;==================================================================== ; subroutine UDIV32 ; 32-Bit / 16-Bit to 32-Bit Quotient & Remainder Unsigned Divide ; ; input: r3, r2, r1, r0 = Dividend X ; r5, r4 = Divisor Y ; ; output: r3, r2, r1, r0 = quotient Q of division Q = X / Y ; r7, r6, r5, r4 = remainder ;; ; alters: acc, flags ;==================================================================== UDIV32: push 08 ; Save Register Bank 1 push 09 push 0AH push 0BH push 0CH push 0DH push 0EH push 0FH push dpl push dph push B setb RS0 ; Select Register Bank 1 mov r7, #0 ; clear partial remainder mov r6, #0 mov r5, #0 mov r4, #0 mov B, #32 ; set loop count div_lp32: clr RS0 ; Select Register Bank 0 clr C ; clear carry flag mov a, r0 ; shift the highest bit of the rlc a ; dividend into... mov r0, a mov a, r1 rlc a mov r1, a mov a, r2 rlc a mov r2, a mov a, r3 rlc a mov r3, a setb RS0 ; Select Register Bank 1 mov a, r4 ; ... the lowest bit of the rlc a ; partial remainder mov r4, a mov a, r5 rlc a mov r5, a mov a, r6 rlc a mov r6, a mov a, r7 rlc a mov r7, a mov a, r4 ; trial subtract divisor from clr C ; partial remainder subb a, 04 mov dpl, a mov a, r5 subb a, 05 mov dph, a mov a, r6 subb a, #0 mov 06, a mov a, r7 subb a, #0 mov 07, a cpl C ; complement external borrow jnc div_321 ; update partial remainder if ; borrow mov r7, 07 ; update partial remainder mov r6, 06 mov r5, dph mov r4, dpl div_321: mov a, r0 ; shift result bit into partial rlc a ; quotient mov r0, a mov a, r1 rlc a mov r1, a mov a, r2 rlc a mov r2, a mov a, r3 rlc a mov r3, a djnz B, div_lp32 mov 07, r7 ; put remainder, saved before the mov 06, r6 ; last subtraction, in bank 0 mov 05, r5 mov 04, r4 mov 03, r3 ; put quotient in bank 0 mov 02, r2 mov 01, r1 mov 00, r0 clr RS0 pop B pop dph pop dpl pop 0FH ; Retrieve Register Bank 1 pop 0EH pop 0DH pop 0CH pop 0BH pop 0AH pop 09 pop 08 ret ;==================================================================== ; subroutine MULDIV ; 16-Bit x 16-Bit to 32-Bit Product Signed Multiply followed by ; 32-Bit / 16-Bit to 32-Bit Quotient & remainder signed Divide ; 2's Complement Format ; ; input: r1, r0 = multiplicand X ; r3, r2 = multiplier Y ; r5, r4 = divisor Z ; ; output: r3, r2, r1, r0 = quotient Q of division Q = (X x Y) / Z ; r7, r6, r5, r4 = remainder ; Carry C is set if Z = 0, i.e. divide by 0 attempted ; ; calls: UMUL16, UDIV32, Cr0r1, Cr2r3, Cr4r5, Mr0r3 ; ; alters: acc, flags, Bits 21H & 22H ;==================================================================== MULDIV: anl PSW, #0E7H ; Register Bank 0 mov a, r4 ; get divisor high byte orl a, r5 ; OR with low byte jnz muld_OK ; divisor OK if not 0 setb C ; else, overflow ret muld_OK: lcall Cr0r1 ; 2's comp -> Mag/Sign lcall Cr2r3 ; 2's comp -> Mag/Sign lcall UMUL16 jb 21H, divn1 ; test X sign divn: lcall Cr4r5 ; 2's comp -> Mag/Sign lcall UDIV32 lcall Mr0r3 ; Mag/Sign -> 2's Comp clr C ; divisor is not 0 ret divn1: jbc 22H, divn ; test Y sign setb 22H sjmp divn ;==================================================================== ; subroutine MACD16 ; 16-Bit x 16-Bit to 32-Bit Product signed Multiply-Accumulate ; with table data and data move. ; y(n) = x(n)*h0 + x(n-1)*h1 + x(n-2)*h2 + ...... ; Note: Assumes shared program/data space. i.e. PSEN and RD are OR-ed ; together on the board. ; 2's Complement format ; ; input: B = No. of 16-bit data items in tables (max 63) ; DPTR --> New Input data (e.g. from ADC) ; DPTR+2 --> Base of Data Table (x) ; DPTR+128 --> Base of Multiplier Table (h) ; ; output: r7, r6, r5, r4 = 32-bit accumulated result ; ; calls: MUL16 ; ; alters: acc, flags, Bits 21H & 22H ;==================================================================== MACD16: anl PSW, #0E7H mov r4, #0 ; Clear Accumulator mov r5, #0 mov r6, #0 mov r7, #0 movx a, @DPTR push acc ; Save XNEWL inc DPTR movx a, @DPTR push acc ; Save XNEWH inc DPTR Macd1: movx a, @DPTR ; Get x(n)L mov r0, a push acc ; Save x(n)L mov a, #80H movc a, @a+DPTR ; Get h(n)L mov r2, a inc DPTR movx a, @DPTR ; Get x(n)H mov r1, a push acc ; Save x(n)H mov a, #80H movc a, @a+DPTR ; Get h(n)H mov r3, a lcall MUL16+3 ; Do Multiply... mov A, r4 ; then Accumulate.. add A, r0 mov r4, A mov A, r5 addc A, r1 mov r5, A mov A, r6 addc A, r2 mov r6, A mov A, r7 addc A, r3 mov r7, A pop 01 ; Now move x data pop 00 pop 03 pop 02 push 00 push 01 mov a, r3 ; Move up x(n)H movx @DPTR, a mov a, #0FFH add a, dpl mov dpl, a mov a, #0FFH addc a, dph mov dph, a mov a, r2 ; Move up x(n)L movx @DPTR, a inc DPTR inc DPTR djnz b, Macd1 ; Whole table processed? dec SP dec SP ret ;================================================================== ; subroutine DELAY ; ; input: r0, r1, r2 = delay loop constants, r0 = coarse loop ;================================================================== DELAY: push dpl push dph mov dpl, r1 mov dph, r2 Delay1: mov r1, dpl Delay2: mov r2, dph djnz r2, $ djnz r1, Delay2 djnz r0, Delay1 pop dph pop dpl ret end