ColdMoney21
ColdMoney21

Reputation: 115

Setting up Sudoku Board

Basically, using ARM assembly code, I'm suppose to load a text file that has the board pattern. Here is what the text file looks like:

704006390
000701500
000090027
002610053
400207008
610039400
930060000
006308000
048900206

(The zeros are blank spaces in a real sudoku puzzle). I have no problem loading the text file. I'm already given the C code on how to check row and columns.

For example, this is to check if the row is okay in C but I have to translate it to arm.

int rowOK(int board[9][9], int row) {
  int index;
  int count[10];

  for (index=0; index<10; index++)
    count[index] = 0;

  for (index=0; index<9; index++)
    count[board[row][index]]++;

  for (index=1; index<10; index++)
    if (count[index] > 1)
      return 0;

  return 1;
}

What I really need help on is on how to approach this. In the ARM language, how do I set up the board so I can start checking and testing? How do I store these numbers from the text file onto memory? Should the numbers be in string format or integers?

int board[9][9]

This code looks like some sort of array. I'm guessing I'm suppose to make an array, but how do I do this in ARM? Any suggestions are appreciated.

Upvotes: 0

Views: 1525

Answers (2)

bstipe
bstipe

Reputation: 282

The text file is in ascii format. The following program will read the text file into memory, put each byte in different register for one row. It can be printed in character format. To change ascii to integer the 'Linux atoi' can do that. The first printed line is from a variable in the program. The second line is from the file red in, indexed to the last line.

/* sudoku.s */

@ sudoku.file
@ 704006390
@ 000701500
@ 000090027
@ 002610053
@ 400207008
@ 610039400
@ 930060000
@ 006308000
@ 048900206

@ ------------------

.data

@ See /usr/include/arm-linux-gnueabihf/asm/unistd.h
@ See /usr/include/arm-linux-gnueabihf/bits/fcntl-linux.h

    .equ create,     8
         .equ Mode, 0644       @ -rw-r--r--
    .equ open,       5
         .equ Rd,   00
         .equ Wr,   01
         .equ RdWr, 02
         .equ Apnd, 02000
    .equ read,       3
    .equ write,      4
    .equ close,      6
    .equ sync,       36
    .equ exit,       1
    .equ sfile,      187

.balign 4
dir_file:
    .asciz "sudoku.file"

.balign 4
Open:
    .word dir_file, Rd, open

.balign 4
Read:
    .word Buf, 91, read

.balign 4
Buf:
    .space 100

.balign 4
Row1:
    .asciz "704006390"

.balign 4
Row2:
    .asciz "000701500"

.balign 4
format:
    .asciz "  | %c  %c  %c | %c  %c  %c | %c  %c  %c |   (num %d )\n"

.balign 4
dec_num:
    .word 0

@ ------------------

.text

.global main

@ -- Subroutine -- Load registers to print --

Load_row:
    ldrb  r1,  [r0], #1
    ldrb  r2,  [r0], #1
    ldrb  r3,  [r0], #1
    ldrb  r4,  [r0], #1
    ldrb  r5,  [r0], #1
    ldrb  r6,  [r0], #1
    ldrb  r7,  [r0], #1
    ldrb  r8,  [r0], #1
    ldrb  r9,  [r0], #1
    @ ldr   r0,  =dec_num    @ The numbers are
    @ str   r1,  [r0]        @   in ascii format. 
    @ push  {r1-r9, lr}      @   This part 
    @ bl    atoi             @   converts ascii
    @ pop   {r1-r9, lr}      @   to integer.
    mov   r10, r0            @ ---- OR ----
    sub   r10, r1, #0x30     @ Under 10, sub hex 30
    mov   pc,  lr

@ -- Subroutine -- Print to stdout --

Prt:
    push  {r0, lr}
    push  {r4-r10}         @ The printf prints
    ldr   r0,  =format     @   r1-r3 and the
    bl    printf           @   rest from
    pop   {r4-r10}         @   the stack.
    pop   {r0, pc}

@ -- Subroutine -- Open, Read file into memory --

Rd_file:
    push  {r0-r12, lr}
    ldr   r3,  =Open
    ldm   r3,  {r0, r1, r7}
    svc   #0
    mov   r4,  r0

    ldr   r3,  =Read
    ldm   r3,  {r1, r2, r7}
    svc   #0

    mov   r0,  r4
    ldr   r7,  =close
    svc   #0
    pop   {r0-r12, lr}
    mov   pc, lr

@ ---- The main program starts here ----

main:

    push  {r4-r10, lr}

@ ---- This is when each row is declared
@      in the .data section ----

    ldr   r0,  =Row1
    bl    Load_row
    bl    Prt

@ ---- This is when reading the file ----

    bl    Rd_file
    ldr   r0,  =Buf
    add   r0,  #80    @ last row
    bl    Load_row
    bl    Prt

End:
    pop   {r4-r10, lr}
    mov   r0,  #0
    bx    lr

.end

Output:

./sudoku; echo $?
  | 7  0  4 | 0  0  6 | 3  9  0 |   (num 7 )
  | 0  4  8 | 9  0  0 | 2  0  6 |   (num 0 )
0

Upvotes: 0

old_timer
old_timer

Reputation: 71516

ARM has nothing to do with it. Either you understand how something like that is arranged in memory or you dont. Once you know how it is arranged then the assembly language is easy.

Looks like your C code is fed an two dimentional array of ints so 32 bits per item. 81 words.

Think about a string

char s[]="hello world";

when you step through items in that string

for(i=0;s[i];s++)

you are generating addresses the base address of the string s, and the an offset which is the index number times the size of each item. So the "e" in hello is at index 1, so base address of s + (offset*size) = s_base + (1*1). and you simply do a byte based load or store at that address (ldrb/strb).

For an array of ints, 32 bits per (one word per) 9x9 is 81 words. like the string the last array value moves by one item at a time [a][b]. incrementing b moves you one word at a time (4 bytes) incrementing a moves you the number of the last allocation times the size of each so int board[d][c] where d and c are numbers each increment of d in C, means c*4 bytes of offset.

basically for your board, using variables board[a][b] board_base_address + (a*(9*4)) + (b*4)

4 being a power of two it gets a little easier board_base_address + ((a*9)<<4) + (b<<2)

9 = 8+1  so a*9 = a*(8+1), distribute = (a*8) + (a*1) = (a<<3) + a

so board_base_address + (a<<7) + (a<<4) + (b<<2) unless I made a typo/mistake somewhere and that is only if you need to calculate random access to the board, for a loop like the one you have you dont need to do that.

implementing the ldr or str is trivial once you have computed the address. If you are comfortable with C you can simply take that C code and continue to break it into smaller parts, get rid of the two dimensional array and make it a single board[81], you are dealing with word addresses not byte so the asm has to add a times 4. (or do the whole thing in bytes if you are allowed, you only need to count to 9).

Hopefully you will see that the problem is the same no matter what architecture, x86, arm, mips, etc. The trick is computing the addresses, the computing of addresses is trivial you just look up the instruction for adding or anding or shifting, etc. And the load and stores are trivial you just look up the instruction for a simple load or store.

basically before you even use the words assembly language do something like this in head or actually implement it

int rowOK(int board[81], int row) {
  int index;
  int count[10];
  int boffset;
  int offset;
  int value;
  int temp;

  index=0;
  do
  {
    count[index]=0;
    index++;
  }
  while(index<10}

  offset = row * 9;
  index=0;
  do
  {
      value=board[offset];
      temp=count[value];
      temp++;
      count[value]=temp;
      offset++;
      index++;
  }
  while(index<9)

  index=1l
  do
  {
      temp=count[index];
      if(temp>1) return(0);
  }
  while(index<10)

  return 1;
}

any and all bugs and typos are intentional...

then it is much easier to just bang out the assembly language directly. Programming has at least two problems to solve, one is the algorithm, two is implementing it. In this case in C but you could use java or pascal or python or whatever and then do the asm as the last step which ever asm you want or need. just keep breaking the problem into smaller individual steps until they resemble things that can be done in one or a few simple instructions.

Of course there is this thing called a compiler you can simply compile the C and the output is assembly language...(much easier to read IMO if you compile to an object then disassemble)...

arm-none-eabi-gcc -O2 -c myfun.c -o myfun.o
arm-none-eabi-objdump -D myfun.o

00000000 <rowOK>:
   0:   27bdffd8    addiu   sp,sp,-40
   4:   03a01021    move    v0,sp
   8:   27a60028    addiu   a2,sp,40
   c:   ac400000    sw  zero,0(v0)
  10:   24420004    addiu   v0,v0,4
  14:   1446fffd    bne v0,a2,c <rowOK+0xc>
  18:   00000000    nop
  1c:   00051080    sll v0,a1,0x2
  20:   00052940    sll a1,a1,0x5
  24:   00452821    addu    a1,v0,a1
  28:   00852021    addu    a0,a0,a1
  2c:   24850024    addiu   a1,a0,36
  30:   8c820000    lw  v0,0(a0)
  34:   24840004    addiu   a0,a0,4
  38:   00021080    sll v0,v0,0x2
  3c:   03a21021    addu    v0,sp,v0
  40:   8c430000    lw  v1,0(v0)
  44:   00000000    nop
  48:   24630001    addiu   v1,v1,1
  4c:   1485fff8    bne a0,a1,30 <rowOK+0x30>
  50:   ac430000    sw  v1,0(v0)
  54:   27a20004    addiu   v0,sp,4
  58:   8c430000    lw  v1,0(v0)
  5c:   00000000    nop
  60:   28630002    slti    v1,v1,2
  64:   10600006    beqz    v1,80 <rowOK+0x80>
  68:   24420004    addiu   v0,v0,4
  6c:   1446fffa    bne v0,a2,58 <rowOK+0x58>
  70:   00000000    nop
  74:   24020001    li  v0,1
  78:   03e00008    jr  ra
  7c:   27bd0028    addiu   sp,sp,40
  80:   00001021    move    v0,zero
  84:   03e00008    jr  ra
  88:   27bd0028    addiu   sp,sp,40

Of course I am not going to give you arm assembly, this is mips...and of course you shouldnt turn in compiler output as your assignment, but it should give you a feel for the instructions you should be looking up in the arm documentation and a feel of how to use them. The compiler is optimizing in this case dont use optimization for at least part of the program to resemble something you should be writing, probably with less stack interaction than unoptimized code is going to generate.

You didnt define if you needed to link this with C or just write some untested code, etc.

Upvotes: 1

Related Questions