#include
#include
// # of rows and columns in each big char
#define CHRSIZE 9
// number of rows in all matrices
#define NROWS 9
// number of columns in display matrix
#define NDCOLS 80
// max length of input string
#define MAXCHARS 100
// number of columns in bigString matrix
// max length of buffer to hold big version
// the +1 allows for one blank column between letters
#define NSCOLS (NROWS * MAXCHARS * (CHRSIZE+1))
#define CLEAR “\033[H\033[2J”
char theString[MAXCHARS+1]; // the input string (from command line)
char display[NROWS][NDCOLS]; // where text place before output
char bigString[NROWS][NSCOLS]; // big char version of input string
#include “chars.h”
void setUpDisplay(int starting, int slength);
void showDisplay();
void delay(int n);
int isUpper(char ch);
int isLower(char ch);
int main(int argc, char **argv)
{
int i, j; // indexes
int row, col; // indexes
int theLength; // length of input string
int bigLength; // length of the bigString
int iterations;
int starting_col;
if (argc < 2) {
printf("Usage: ./scroll String\n");
return 1;
}
// copy the input string
theLength = 0;
for (char *s = argv[1]; *s != '\0'; s++) {
char ch = *s;
if (!isUpper(ch) && !isLower(ch) && ch != ' ') {
printf("Only letters and spaces are allowed in the string!\n");
exit(1);
}
if (theLength >= MAXCHARS) break;
theString[theLength] = ch;
theLength++;
}
theString[theLength] = ‘\0’;
bigLength = theLength * (CHRSIZE+1);
// check the command-line arg (the string)
if (theLength >= MAXCHARS) {
printf(“String must be < %d chars\n", MAXCHARS);
return 1;
}
if (theLength < 1) {
printf("Please enter a string with at least one character!\n");
exit(1);
}
// initialise the display to all spaces
for (i = 0; i < NROWS; i++) {
for (j = 0; j < NDCOLS; j++)
display[i][j] = ' ';
}
// create the bigchars array
for (i = 0; i < theLength; i++) {
char ch = theString[i];
if (ch == ' ') {
for (row = 0; row < CHRSIZE; row++) {
for (col = 0; col < CHRSIZE; col++)
bigString[row][col + i * (CHRSIZE+1)] = ' ';
}
}
else {
int which;
// calculate index of the char in all_chars
if (isUpper(ch)) which = ch - 'A';
if (isLower(ch)) which = ch - 'a' + 26;
for (row = 0; row < CHRSIZE; row++) {
for (col = 0; col < CHRSIZE; col++) {
// copy char to the buffer
bigString[row][col + i * (CHRSIZE+1)] = all_chars[which][row][col];
}
}
}
col = (i * (CHRSIZE+1)) + CHRSIZE;
for (row = 0; row < CHRSIZE; row++)
bigString[row][col] = ' ';
}
// enough to scroll it completely off the left
iterations = NDCOLS+bigLength;
// starting_col says how far across the display to start the text
starting_col = NDCOLS-1;
for (i = 0; i < iterations; i++) {
setUpDisplay(starting_col, bigLength);
showDisplay();
// note that starting_col can go negative
// in which case we show the string starting from part-way through
starting_col--;
delay(1);
}
return 0;
}
void setUpDisplay(int starting, int length)
{
int row; // current row in display and bigString
int out_col; // index of current column in display
int in_col; // index of current column in bigString
int first_col; // which column to start from in bigString
if (starting < 0) {
// start part-way through bigString
// it's scrolling off the left of the display
out_col = 0;
first_col = -starting;
}
else {
// blank out the part of the display before the string
for (out_col = 0; out_col < starting; out_col++) {
for (row = 0; row < NROWS; row++)
display[row][out_col] = ' ';
}
first_col = 0;
}
// copy the relevant bits of the bigString into the display
for (in_col = first_col; in_col < length; in_col++) {
if (out_col >= NDCOLS) break;
for (row = 0; row < NROWS; row++) {
display[row][out_col] = bigString[row][in_col];
}
out_col++;
}
}
// dump the contents of display[][] to stdout
void showDisplay()
{
printf(CLEAR);
for (int i = 0; i < NROWS; i++) {
for (int j = 0; j < NDCOLS; j++)
putchar(display[i][j]);
putchar('\n');
}
}
// waste some time
void delay(int n)
{
int x = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < 20000; j++)
for (int k = 0; k < 1000; k++)
x = x + 1;
}
}
// check for an upper-case alphabetic
int isUpper(char ch)
{
if (ch >= ‘A’ && ch <= 'Z')
return 1;
else
return 0;
}
// check for a lower-case alphabetic
int isLower(char ch)
{
if (ch >= ‘a’ && ch <= 'z')
return 1;
else
return 0;
}
# Scroll letters from a message in argv[1] # # Base code by Jashank Jeremy # Tweaked by John Shepherd # $Revision: 1.5 $ # # Edit me with 8-column tabs!
# Requires:
# - `all_chars', defined in chars.s
# Provides:
.globl main # :: int, [char *], [char *] -> int
.globl setUpDisplay # :: int, int -> void
.globl showDisplay # :: void -> void
.globl delay # :: int -> vovid
.globl isUpper # :: char -> int
.globl isLower # :: char -> int
.globl CHRSIZE
.globl NROWS
.globl NDCOLS
.globl MAXCHARS
.globl NSCOLS
.globl CLEAR
########################################################################
.data
# /!\ NOTE /!\
# In C, the values of the symbols `CHRSIZE’, `NROWS’, `NDCOLS’,
# `NSCOLS’, `MAXCHARS’, and `CLEAR’ would be substituted during
# preprocessing. SPIM does not have preprocessing facilities,
# so instead we provide these values in the `.data’ segment.
# # of rows and columns in each big char
CHRSIZE: .word 9
# number of rows in all matrices
NROWS: .word 9
# number of columns in display matrix
NDCOLS: .word 80
# max length of input string
MAXCHARS: .word 100
# number of columns in bigString matrix
# max length of buffer to hold big version
# the +1 allows for one blank column between letters
NSCOLS: .word 9000 # (NROWS * MAXCHARS * (CHRSIZE + 1))
# ANSI escape sequence for ‘clear-screen’
CLEAR: .asciiz “\033[H\033[2J”
# CLEAR: .asciiz “__showpage__\n” # for debugging
main__0: .asciiz “Usage: ./scroll String\n”
main__1: .asciiz “Only letters and spaces are allowed in the string!\n”
main__2: .asciiz “String mush be < "
main__3: .asciiz " chars\n"
main__4: .asciiz "Please enter a string with at least one character!\n"
.align 4
theString: .space 101 # MAXCHARS + 1
.align 4
display: .space 720 # NROWS * NDCOLS
.align 4
bigString: .space 81000 # NROWS * NSCOLS
########################################################################
# .TEXT
.text
main:
# Frame: $fp, $ra, …
# Uses: $a0, $a1, $t0, $t1, $t2, $s0, $s1
# Clobbers: …
# Locals:
# – `theLength’ in $s0
# – `bigLength’ in $s1
# – `ch’ in $s2
# – `str’ in $t2
# – `i’ in $…
# – `j’ in $…
# – `row’ in $…
# – `col’ in $…
# – `iterations’ in $…
# – `startingCol’ in $…
# Structure:
# main
# -> [prologue]
# -> main_argc_gt_two
# -> main_PTRs_init
# -> main_PTRs_cond
# -> main_ch_notspace
# -> main_ch_isLower
# -> main_ch_isSpace
# -> main_PTRs_step
# -> main_PTRs_f
# [theLength cond]
# | main_theLength_ge_MAXCHARS
# | main_theLength_lt_MAXCHARS
# | main_theLength_lt_1
# | main_theLength_ge_1
# …
# -> [epilogue]
# Code:
# set up stack frame
sw $fp, -4($sp)
la $fp, -4($sp)
sw $ra, -4($fp) # note: switch to $fp-relative
sw $s0, -8($fp)
sw $s1, -12($fp)
sw $s2, -16($fp)
addi $sp, $sp, -20
# if (argc < 2)
li $t0, 2
bge $a0, $t0, main_argc_gt_two
nop # in delay slot
# printf(...)
la $a0, main__0
li $v0, 4 # PRINT_STRING_SYSCALL
syscall
# return 1 => load $v0, jump to epilogue
li $v0, 1
j main__post
nop # in delay slot
main_argc_gt_two:
move $s0, $zero
main_PTRs_init:
# s = argv[1]
lw $t2, 4($a1)
main_PTRs_cond:
# optimisation: `ch = *s’ now
# (ch = )*s
lb $s2, ($t2)
# *s != ‘\0’ => ch != 0
beqz $s2, main_PTRs_f
nop # in delay slot
# if (!isUpper(ch))
main_ch_upper:
move $a0, $s2
jal isUpper
nop # in delay slot
beqz $v0, main_ch_lower
nop # in delay slot
j main_ch_ok
nop # in delay slot
# if (!isLower(ch))
main_ch_lower:
move $a0, $s2
jal isLower
nop # in delay slot
beqz $v0, main_ch_space
nop # in delay slot
j main_ch_ok
nop # in delay slot
# if (ch != ‘ ‘)
main_ch_space:
li $t0, ‘ ‘
bne $s2, $t0, main_ch_fail
nop # in delay slot
j main_ch_ok
nop # in delay slot
main_ch_fail:
# printf(…)
la $a0, main__1
li $v0, 4 # PRINT_STRING_SYSCALL
syscall
# exit(1) => return 1 => load $v0, jump to epilogue
li $v0, 1
j main__post
nop # in delay slot
main_ch_ok:
# if (theLength >= MAXCHARS)
la $t0, MAXCHARS
lw $t0, ($t0)
# break => jump out of for(*s…)
bge $s0, $t0, main_PTRs_f
# theString[theLength]
la $t0, theString
addu $t0, $t0, $s0 # ADDU because address
# theString[theLength] = ch
sb $s2, ($t0)
# theLength++
addi $s0, $s0, 1
main_PTRs_step:
# s++ => s = s + 1
addiu $t2, $t2, 1 # ADDIU because address
j main_PTRs_cond
nop
main_PTRs_f:
# theString[theLength] = …
la $t0, theString
addu $t0, $t0, $s0 # ADDU because address
# theString[theLength] = ‘\0’
sb $zero, ($t0)
# CHRSIZE + 1
la $t0, CHRSIZE
lw $t0, ($t0)
addi $t0, $t0, 1
# bigLength = theLength * (CHRSIZE + 1)
mul $s1, $t0, $s0
# if (theLength >= MAXCHARS)
la $t0, MAXCHARS
lw $t0, ($t0)
blt $s0, $t0, main_theLength_lt_MAXCHARS
nop # in delay slot
main_theLength_ge_MAXCHARS:
# printf(…, …, …)
la $a0, main__2
li $v0, 4 # PRINT_STRING_SYSCALL
syscall
move $a0, $t0
li $v0, 1 # PRINT_INT_SYSCALL
syscall
la $a0, main__3
li $v0, 4 # PRINT_STRING_SYSCALL
syscall
# return 1 => load $v0, jump to epilogue
li $v0, 1
j main__post
nop # in delay slot
main_theLength_lt_MAXCHARS:
# if (theLength < 1)
li $t0, 1
bge $s0, $t0, main_theLength_ge_1
nop # in delay slot
main_theLength_lt_1:
# printf(...)
la $a0, main__4
li $v0, 4 # PRINT_STRING_SYSCALL
syscall
# exit(1) => return 1 => load $v0, jump to epilogue
li $v0, 1
j main__post
nop # in delay slot
main_theLength_ge_1:
# … TODO …
# return 0
move $v0, $zero
main__post:
# tear down stack frame
lw $s2, -16($fp)
lw $s1, -12($fp)
lw $s0, -8($fp)
lw $ra, -4($fp)
la $sp, 4($fp)
lw $fp, ($fp)
jr $ra
nop # in delay slot
########################################################################
# .TEXT
.text
setUpDisplay:
# Frame: $fp, $ra, …
# Uses: $a0, $a1, …
# Clobbers: …
# Locals:
# – `row’ in $…
# – `out_col’ in $…
# – `in_col’ in $…
# – `first_col’ in $…
# – …
# Structure:
# setUpDisplay
# -> [prologue]
# -> …
# -> [epilogue]
# Code:
# set up stack frame
sw $fp, -4($sp)
la $fp, -4($sp)
sw $ra, -4($fp)
la $sp, -8($fp)
# … TODO …
# tear down stack frame
lw $ra, -4($fp)
la $sp, 4($fp)
lw $fp, ($fp)
jr $ra
nop # in delay slot
########################################################################
# .TEXT
.text
showDisplay:
# Frame: $fp, $ra, …
# Uses: …
# Clobbers: …
# Locals:
# – `i’ in $…
# – `j’ in $…
# – …
# Structure:
# showDisplay
# -> [prologue]
# -> …
# -> [epilogue]
# Code:
# set up stack frame
sw $fp, -4($sp)
la $fp, -4($sp)
sw $ra, -4($fp)
la $sp, -8($fp)
# … TODO …
# tear down stack frame
lw $ra, -4($fp)
la $sp, 4($fp)
lw $fp, ($fp)
jr $ra
nop # in delay slot
########################################################################
# .TEXT
.text
delay:
# Frame: $fp, $ra
# Uses: $a0, $t0, $t1, $t2, $t3, $t4, $t5
# Clobbers: $t0, $t1, $t2, $t3, $t4, $t5
# Locals:
# – `n’ in $a0
# – `x’ in $t0
# – `i’ in $t1
# – `j’ in $t2
# – `k’ in $t3
# Structure:
# delay
# -> [prologue]
# -> delay_i_init
# -> delay_i_cond
# -> delay_j_init
# -> delay_j_cond
# -> delay_k_init
# -> delay_k_cond
# -> delay_k_step
# -> delay_k_f
# -> delay_j_step
# -> delay_j_f
# -> delay_i_step
# -> delay_i_f
# -> [epilogue]
# Code:
sw $fp, -4($sp)
la $fp, -4($sp)
sw $ra, -4($fp)
la $sp, -8($fp)
# x <- 0
move $t0, $zero
# These values control the busy-wait.
li $t4, 20000
li $t5, 1000
delay_i_init:
# i = 0;
move $t1, $zero
delay_i_cond:
# i < n;
bge $t1, $a0, delay_i_f
nop # in delay slot
delay_j_init:
# j = 0;
move $t2, $zero
delay_j_cond:
# j < DELAY_J;
bge $t2, $t4, delay_j_f
nop # in delay slot
delay_k_init:
# k = 0;
move $t3, $zero
delay_k_cond:
# k < DELAY_K;
bge $t3, $t5, delay_k_f
nop # in delay slot
# x = x + 1
addi $t0, $t0, 1
delay_k_step:
# k = k + 1
addi $t3, $t3, 1
j delay_k_cond
nop # in delay slot
delay_k_f:
delay_j_step:
# j = j + 1
addi $t2, $t2, 1
j delay_j_cond
nop # in delay slot
delay_j_f:
delay_i_step:
# i = i + 1
addi $t1, $t1, 1
j delay_i_cond
nop # in delay slot
delay_i_f:
delay__post:
# tear down stack frame
lw $ra, -4($fp)
la $sp, 4($fp)
lw $fp, ($fp)
jr $ra
nop # in delay slot
########################################################################
# .TEXT
.text
isUpper:
# Frame: $fp, $ra, …
# Uses: $a0, …
# Clobbers: $v0, …
# Locals:
# – …
# Structure:
# isUpper
# -> [prologue]
# -> [epilogue]
# Code:
# set up stack frame
# … TODO …
# tear down stack frame
jr $ra
nop # in delay slot
########################################################################
# .TEXT
.text
isLower:
# Frame: $fp, $ra
# Uses: $a0
# Clobbers: $v0
# Locals:
# – `ch’ in $a0
# – … $v0 used as temporary register
# Structure:
# isLower
# -> [prologue]
# [ch cond]
# | isLower_ch_ge_a
# | isLower_ch_le_z
# | isLower_ch_lt_a
# | isLower_ch_gt_z
# -> isLower_ch_phi
# -> [epilogue]
# Code:
# set up stack frame
sw $fp, -4($sp)
la $fp, -4($sp)
sw $ra, -4($fp)
la $sp, -8($fp)
# if (ch >= ‘a’)
li $v0, ‘a’
blt $a0, $v0, isLower_ch_lt_a
nop # in delay slot
isLower_ch_ge_a:
# if (ch <= 'z')
li $v0, 'z'
bgt $a0, $v0, isLower_ch_gt_z
nop # in delay slot
isLower_ch_le_z:
addi $v0, $zero, 1
j isLower_ch_phi
nop # in delay slot
# ... else
isLower_ch_lt_a:
isLower_ch_gt_z:
move $v0, $zero
# fallthrough
isLower_ch_phi:
isLower__post:
# tear down stack frame
lw $ra, -4($fp)
la $sp, 4($fp)
lw $fp, ($fp)
jr $ra
nop # in delay slot