Please explain why deadlock is detected in my example
Simplified version

drop table TabA;
create table TabA ( a int
,                   b int );
insert into TabA
values ( 1, 11 ),
    ( 2, 22 ),
    ( 3, 333 );
select * from TabA;

--T1. Run T1 first.
begin tran t1
insert into TabA values (5, 55 );

waitfor delay '00:00:10';
--Run T2 in the other session within 10 sec. 

-- After delay expires deadlock is detected 
select * from TabA where a = 2;

commit tran t1;


Second script

--T2. 
begin tran t2
update TabA set b = 111 where a=1;
commit tran t2;


Looking at deadlock graph (MS SQL 2008 Profiler), you'll see

1) T1 has inserted (5,555) row and holds X lock on this RID untill commit.  

2) T2 tries to get U lock on all rows, check predicate a=1 and update the rows where the predicate evaluates to true.
2.1. It successfully updates one a=1 row and holds X lock on this RID untill commit.
2.2. When T2 tries to get U lock on (5,555) row it can't do that due to T1's lock. So T2 waits for T1 to commit. 

3) After delay T1 tries to get S lock on all rows when executing SELECT * FROM TabA ... and naturally it can't obtain the lock on the row held by T2 (see 2.1). T1 must wait T2 which waits T1. Deadlock.

Now add PK to TabA

create table TabA ( a int PRIMARY KEY,
                   b int );


Sql sever is now deadly sure it needn't check any more rows for a=1 at step(2.1). T2 commits immediately and no dead lock detected.