; Assessment, Excersise 3 ; ; Program to count the frequenct of occurance ; of each character in a file ; ; By Andy Bennett (andyjpb@ashurst.eu.org), 2002 AREA charFreq, CODE, READONLY ; declare code area SWI_Exit EQU 0x11 ; finish program SWI_Open EQU 0x66 ; open a file or device SWI_Close EQU 0x68 ; close an open file or device SWI_Read EQU 0x6a ; read from an open file or device SWI_Flen EQU 0x6c ; returns the current length of an open file or device SWI_Write EQU 0x69 ; write to an open file or device SWI_WriteC EQU 0x0 ; write a character to the console SWI_Write0 EQU 0x2 ; write a null terminated string to the console readonly EQU 0 ; open a file or device for reading writeonly EQU 4 ; open a file or device for writing ENTRY ; code entry point START ADR r0, INFILE ; set r0 to point to INFILE MOV r1, #readonly ; set access mode to file as readonly SWI SWI_Open ; open the file pointed at by r0 CMP r0, #0 ; check for success on opening file SWIEQ SWI_Exit ; if file could not be opened then exit now MOV r5, r0 ; save the file handle in r5 for later SWI SWI_Flen ; store the length of the file in r0 CMP r0, #-1 ; check that the call was successful SWIEQ SWI_Exit ; if the call failed then exit now MOV r6, r0 ; move the length of the file into r6 MOV r2, #1 ; read the file byte by byte MOV r8, #4 ; store constant in register to keep MUL happy ADR r0, FREQARRAY ; point r1 at the beginning of FREQARRAY MOV r1, #0 ; initialise loop counter MOV r3, #0 ; prepare to initialise FREQARRAY to 0 INITARRAY STR r3, [r0, r1] CMP r1, #112 ; check to see if we are at the end of FREQARRAY BGT COUNT ; once memory is initialised, begin counting ADD r1, r1, #4 ; move along FREQARRAY by one word B INITARRAY ; continue looping COUNT CMP r6, #0 ; are we at the end of the file BEQ ENDCOUNT ; if so, go to the next bit of code ADR r1, FILECONTENTS ; if not, point r1 at the temp storage space MOV r0, r5 ; retrive the file handle from r5 SWI SWI_Read ; read the byte in CMP r0, #0 ; check that the call was sucessful BNE ENDCOUNT ; if anything was left unread, then end of file encountered prematurely so wrap up LDRB r4, [r1] ; load byte into the register CMP r4, #9 ; is it a tab (white space) MOVEQ r3, #104 ; move along FREQARRAY 26 words (26x4) to the "whitespace" word BEQ UPDATEFREQ ; "subroutine" to update FREQARRAY CMP r4, #10 ; is it a line feed (white space) MOVEQ r3, #26 ; move along FREQARRAY 26 words to the "whitespace" word BEQ UPDATEFREQ ; "subroutine" to update FREQARRAY CMP r4, #13 ; is it a carriage return (white space) MOVEQ r3, #26 ; move along FREQARRAY 26 words to the "whitespace" word BEQ UPDATEFREQ ; "subroutine" to update FREQARRAY CMP r4, #32 ; is it a space (white space) MOVEQ r3, #26 ; move along FREQARRAY 26 words to the "whitespace" word BEQ UPDATEFREQ ; "subroutine" to update FREQARRAY ; deal with upper case letters CMP r4, #65 ; is it >= 65 BLT LITTLECMP CMP r4, #90 ; or <= 90 SUBLE r3, r4, #65 ; move along FREQARRAY (r4 - #65) words to the correct letter BLE UPDATEFREQ ; "subroutine" to update FREQARRAY ; deal with lower case letters LITTLECMP CMP r4, #97 ; is it >= 97 BLT OTHERS CMPGE r4, #122 ; or <= 122 SUBLE r3, r4, #97 ; move along FREQARRAY (r4 - #97) words to the correct letter BLE UPDATEFREQ ; "subroutine" to update FREQARRAY ; deal with other characters OTHERS MOV r3, #27 ; move along FREQARRAY 27 words to the "others" word UPDATEFREQ ADR r4, FREQARRAY ; point r4 at the start of FREQARRAY MUL r7, r3, r8 ; multiply offset in words by 4 so that value is in bytes ADD r4, r4, r7 ; move along FREQARRAY to the correct word LDR r3, [r4] ; load the correct word into r3 ADD r3, r3, #1 ; add one to the count STR r3, [r4] ; write r3 back to memory again SUB r6, r6, #1 ; move along to the next byte in the file B COUNT ; resume processing with the next character in the file ENDCOUNT MOV r0, r5 ; move the file handle into r0 SWI SWI_Close ; close the file ADR r1, FREQARRAY ; place the start of FREQARRAY into r1 ADR r2, FILECONTENTS MOV r6, #0 ; initialise counter, r6, to 0 REPORT CMP r6, #27 ; check loop counter BGT ENDREPORT ; if >28 go to ENDREPORT MUL r7, r6, r8 ; multiply offset in words by 4 so that value is in bytes LDR r3, [r1, r7] ; load the current value into r3 CMP r6, #25 ; see if we are still on the alpha characters ADDLE r0, r6, #65 ; if we are, put the current ascii value into r0 SWILE SWI_WriteC ; if we are, write out the character we are on CMP r6, #26 ; see if we are on "White Spaces" ADREQ r0, TXTWHITE ; if we are, point r0 at white spaces string SWIEQ SWI_Write0 ; if we are, write out the white spaces string CMP r6, #27 ; see if we are on "Others" ADREQ r0, TXTOTHERS ; if we are, point r0 at others string SWIEQ SWI_Write0 ; if we are, write out the others string MOV r0, #58 ; then we want a colon, so set it up SWI SWI_WriteC ; and write it out MOV r0, #32 ; then we want a space, so set it up SWI SWI_WriteC ; and write it out BL HEXOUT ; write value to console in hexadecimal MOV r0, #10 ; then we want a carriage return, so set it up SWI SWI_WriteC ; and write it out ADD r6, r6, #1 ; increment loop counter B REPORT ; continue round loop with next item ENDREPORT SWI SWI_Exit ; end program ; subroutines ; subroutine to output values in hex to the console HEXOUT STMED r13!, {r0-r8, r14} ; save working registers on stack MOV r2, #8 ; r2 has nibble (4-bit digit) count = 8 MOV r4, #0 ; initialise flag HEXLOOP MOV r0, r3, LSR #28 ; get top nibble CMP r0, #9 ; if nibble <= 9, then ADDLE r0, r0, #"0" ; convert to ASCII numeric char ADDGT r0, r0, #"A"-10 ; else convert to ASCII alphabet char CMP r0, #"0" ; do we have a zero... MOVNE r4, #1 ; if not, set the flag BNE HEXNOTZERO ; if not, get the digit written out immediately CMP r4, #0 ; ... and the flag is not set BEQ HEXLEADZERO ; do not write out leading zeros HEXNOTZERO SWI SWI_WriteC ; print character HEXLEADZERO MOV r3, r3, LSL #4 ; shift left 4 bits to get to next nibble SUBS r2, r2, #1 ; decrement nibble count BNE HEXLOOP ; if more, do next nibble LDMED r13!, {r0-r8, pc} ; retrieve working registers from stack ; ... and return to calling program INFILE = "turing.txt", 0 ; input filename + null ALIGN ; align variables on 32bit boundries TXTWHITE = "White Spaces", 0 ; Text for report + null TXTOTHERS = "Others", 0 ; Text for report + null FILECONTENTS = "a" ; one byte to store one character from the file in whilst we process it ALIGN ; align variables on 32bit boundries FREQARRAY = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ; 28 words for storing the frequency of each character. Init to "0" END