Code:
.data
matrix: .word 1000,4246,4850,54,3945,3192,3436,2586,2189,925,3814
.word 2363,2464,101,1362,2341,1596,4172,2929,2677,2435
.word 4033,2225,2598,4070,704,2052,64,4682,2964,1332
.word 2879,772,3829,170,3475,1261,153,1005,497,1721
.word 162,4664,4493,4786,1693,2876,2530,3177,2706,1229
.word 208,2332,1061,3585,4145,4795,1071,890,504,4109
.word 2761,3877,2894,4591,807,3651,3186,3732,2085,557
.word 4173,145,4681,4060,599,3391,4820,166,2273,1003
.word 2230,1309,3008,850,4509,505,4826,4726,2898,1718
.word 3497,1358,2272,3752,2433,4577,3545,4147,3512
; s1:14
; s2:f
; s3:19
; s4:12
; s5:16
hits: .word 0,0,0,0,0,0,0,0
CONTROL: .word32 0x10000
DATA: .word32 0x10008
DIVIDE: .word 0x20C49C ; if I move this below the next line it won't load it (???)
mes: .asciiz "Invalid number \:\n" ; error message
.code
lwu $t4,DIVIDE($zero) ; t4 == 2^31 / 1000
daddi $t1, $zero, matrix ; t1 == start of the array
daddi $s7, $t1, 800 ; s7 == end of the array
daddi $t3, $zero, hits ; t3 == start of the hits array
first_iteration:
lwu $t0,($t1) ; load value to t0
daddi $t1, $t1, 8 ; increment address
dmulu $t2, $t0, $t4 ; multiply by 2147484 - ! unsigned
dsra $t8, $t2, 31 ; right shift
; up till now we have divided by 1000 - valid for the range we care
loop:
lwu $t0,($t1) ; load value to t0
slti $t7, $t8, 5 ; meanwhile check for error
dmulu $t2, $t0, $t4 ; multiply by 2147484 - ! unsigned
; meanwhile store the previous result !
dsll $t6, $t8, 3 ; multiply by 8 to get the offset
lwu $t5, hits($t6) ; load the value from hits
beqz $t7, error ; if t2 was more than 4 error
daddi $t1, $t1, 8 ; increment address
daddi $t5, $t5, 1 ; increment it ! STRUCTURAL HAZARD
dsra $t8, $t2, 31 ; right shift
; up till now we have divided by 1000
sd $t5, hits($t6) ; store it back
; result stored !
condition:
bne $t1,$s7,loop
;store the last result and check for error !
slti $t7, $t8, 5 ; meanwhile check for error
dsll $t6, $t8, 3 ; multiply by 8 to get the offset
beqz $t7, error ; if t2 was more than 4 error !
lwu $t5, hits($t6) ; load the value from hits
daddi $t5, $t5, 1 ; increment it
sd $t5, hits($t6) ; store it back
; load the registers
lwu $s1, ($t3)
lwu $s2, 8($t3)
lwu $s3, 16($t3)
lwu $s4, 24($t3)
lwu $s5, 32($t3)
halt
error:
; needed for printing
lwu $s0,DATA($zero) ; $s0 = address of DATA register
lwu $s6,CONTROL($zero) ; $s6 = address of CONTROL register
; end printing
daddi $v0,$zero,4 ; set for ascii output
daddi $t0,$zero,mes
sd $t0,0($s0) ; write address of message to DATA register
sd $v0,0($s6) ; make it happen
daddi $t1, $t1, -8 ; decrement address
ld $t0,($t1) ; load value to t0
daddi $v0,$zero,2 ; set for signed integer output
sd $t0,0($s0) ; write integer to DATA register
sd $v0,0($s6) ; make it happen
halt
Runs in 1223 cycles with branch buffer ON - but notice I abort on error, which adds error checking while in the loop ! The checks for < 0 are not needed as in the unsigned arithmetics negative numbers are much larger than 5000. The code looks a bit messed up cause I moved instructions around to avoid RAW, WAW etc hazards. Namely I store the results and error check _on the next iteration of the loop_ so I am kept busy during multiplication.