Download as pdf or txt
Download as pdf or txt
You are on page 1of 69

Introduction to Computing Systems:

From Bits & Gates to C & Beyond 3rd


Edition Yale Patt - eBook PDF
Go to download the full and correct content document:
https://ebooksecure.com/download/introduction-to-computing-systems-from-bits-gate
s-to-c-beyond-ebook-pdf/
More products digital (pdf, epub, mobi) instant
download maybe you interests ...

(eBook PDF) Introduction to Information Systems 3rd


Edition

http://ebooksecure.com/product/ebook-pdf-introduction-to-
information-systems-3rd-edition/

Introduction to Computing 1st Edition David A. Joyner -


eBook PDF

https://ebooksecure.com/download/introduction-to-computing-ebook-
pdf/

(eBook PDF) Processes, Systems, and Information: An


Introduction to MIS 3rd Edition

http://ebooksecure.com/product/ebook-pdf-processes-systems-and-
information-an-introduction-to-mis-3rd-edition/

Introduction to Criminal Justice: Systems, Diversity,


and Change 3rd Edition (eBook PDF)

http://ebooksecure.com/product/introduction-to-criminal-justice-
systems-diversity-and-change-3rd-edition-ebook-pdf/
(eBook PDF) Introduction to Information Systems:
People, Technology and Processes 3rd Edition

http://ebooksecure.com/product/ebook-pdf-introduction-to-
information-systems-people-technology-and-processes-3rd-edition/

(Textbook) Introduction to Information Systems 6th


Edition

http://ebooksecure.com/product/textbook-introduction-to-
information-systems-6th-edition/

(eBook PDF) Human Physiology From Cells to Systems 9th


Edition

http://ebooksecure.com/product/ebook-pdf-human-physiology-from-
cells-to-systems-9th-edition/

(eBook PDF) C++ Programming: From Problem Analysis to


Program Design 7th

http://ebooksecure.com/product/ebook-pdf-c-programming-from-
problem-analysis-to-program-design-7th/

(Original PDF) C++ Programming From Problem Analysis to


Program Design 8th

http://ebooksecure.com/product/original-pdf-c-programming-from-
problem-analysis-to-program-design-8th/
third edition

introduction
to computing
systems
from bits & gates to
C/C++ & beyond

yale n. patt
sanjay j. patel
introduction to
computing systems
third edition

introduction to
computing systems
from bits & gates to C/C++ & beyond

Yale N. Patt
The University of Texas at Austin

Sanjay J. Patel
University of Illinois at Urbana-Champaign
INTRODUCTION TO COMPUTING SYSTEMS: FROM BITS & GATES TO C/C++ & BEYOND, THIRD EDITION

Published by McGraw-Hill Education, 2 Penn Plaza, New York, NY 10121. Copyright 2020 c by McGraw-Hill Education. All rights
reserved. Printed in the United States of America. Previous editions 2004,
c and 2001. No part of this publication may be reproduced
or distributed in any form or by any means, or stored in a database or retrieval system, without the prior written consent of McGraw-Hill
Education, including, but not limited to, in any network or other electronic storage or transmission, or broadcast for distance learning.

Some ancillaries, including electronic and print components, may not be available to customers outside the United States.

This book is printed on acid-free paper.

1 2 3 4 5 6 7 8 9 LCR 24 23 22 21 20 19

ISBN 978-1-260-15053-7 (bound edition)


MHID 1-260-15053-4 (bound edition)
ISBN 978-1-260-42474-4 (loose-leaf edition)
MHID 1-260-42474-X (loose-leaf edition)

Executive Portfolio Manager: Suzy Bainbridge


Product Developer: Heather Ervolino
Senior Marketing Manager: Shannon O’Donnell
Content Project Manager: Jeni McAtee
Buyer: Sandy Ludovissy
Designer: David Hash
Content Licensing Specialist: Melissa Homer
Cover Image: Front Cover Computing art Yale c N. Patt; Abstract image in green, orange and yellow Design
c Pics/Tim Antoniuk;
Abstract image in orange, green and yellow Design
c Pics/Tim Antoniuk; Computer laptops on a blue abstract background loops7/
c
Getty Images; Illustration of streams of binary code Shutterstock/Tavarius
c
Compositor: Aptara R
, Inc.

All credits appearing on page or at the end of the book are considered to be an extension of the copyright page.

Library of Congress Cataloging-in-Publication Data


Names: Patt, Yale N., author. Patel, Sanjay J., author.
Title: Introduction to computing systems : from bits & gates to c/c++ &
beyond / Yale N. Patt, The University of Texas at Austin, Sanjay J. Patel,
University of Illinois at Urbana-Champaign.
Description: Third edition. New York, NY : McGraw-Hill, 2020.
Identifiers: LCCN 2018050089 ISBN 9781260150537 (acid-free paper) ISBN
1260150534 (acid-free paper)
Subjects: LCSH: Computer science. C (Computer program language)
Classification: LCC QA76 .P367 2019 DDC 004–dc23 LC record available at
https://lccn.loc.gov/2018050089

The Internet addresses listed in the text were accurate at the time of publication. The inclusion of a website does not indicate an endorse-
ment by the authors or McGraw-Hill Education, and McGraw-Hill Education does not guarantee the accuracy of the information presented
at these sites.

mheducation.com/highered
To the memory of my parents,
Abraham Walter Patt A"H and Sarah Clara Patt A"H,
who taught me to value “learning”
even before they taught me to ride a bicycle.

To my loving family,
Amita, Kavi, and Aman.
Contents

Preface xv 2.4 Conversion Between Binary and Decimal 31


2.4.1 Binary to Decimal Conversion 31
2.4.2 Decimal to Binary Conversion 32
2.4.3 Extending Conversion to Numbers with
1 Welcome Aboard 1 Fractional Parts 33
1.1 What We Will Try to Do 1
2.5 Operations on Bits—Part I: Arithmetic 34
1.2 How We Will Get There 1
2.5.1 Addition and Subtraction 34
1.3 Two Recurring Themes 3
2.5.2 Sign-Extension 36
1.3.1 The Notion of Abstraction 3
2.5.3 Overflow 36
1.3.2 Hardware vs. Software 5
2.6 Operations on Bits—Part II: Logical
1.4 A Computer System 7
Operations 38
1.4.1 A (Very) Little History for a (Lot)
2.6.1 A Logical Variable 38
Better Perspective 8
2.6.2 The AND Function 38
1.4.2 The Parts of a Computer
2.6.3 The OR Function 39
System 10
2.6.4 The NOT Function 40
1.5 Two Very Important Ideas 11
2.6.5 The Exclusive-OR Function 40
1.6 Computers as Universal
2.6.6 DeMorgan’s Laws 41
Computational Devices 12
2.6.7 The Bit Vector 42
1.7 How Do We Get the Electrons to Do
2.7 Other Representations 43
the Work? 14
2.7.1 Floating Point Data Type (Greater Range,
1.7.1 The Statement of the Problem 14
Less Precision) 43
1.7.2 The Algorithm 16
2.7.2 ASCII Codes 47
1.7.3 The Program 16
2.7.3 Hexadecimal Notation 48
1.7.4 The ISA 17
Exercises 49
1.7.5 The Microarchitecture 18
1.7.6 The Logic Circuit 19
1.7.7 The Devices 19
Exercises 20 3 Digital Logic Structures 59
3.1 The Transistor 59
3.2 Logic Gates 61
3.2.1 The NOT Gate (Inverter) 61
2 Bits, Data Types, 3.2.2 OR and NOR Gates 62
and Operations 25 3.2.3 Why We Can’t Simply Connect P-Type
2.1 Bits and Data Types 25 to Ground 64
2.1.1 The Bit as the Unit of Information 25 3.2.4 AND and NAND Gates 65
2.1.2 Data Types 26 3.2.5 Gates with More Than Two Inputs 66
2.2 Integer Data Types 26 3.3 Combinational Logic Circuits 67
2.2.1 Unsigned Integers 26 3.3.1 Decoder 67
2.2.2 Signed Integers 27 3.3.2 Mux 68
2.3 2’s Complement Integers 29 3.3.3 A One-Bit Adder (a.k.a. a Full Adder) 69
viii Contents

3.3.4 The Programmable Logic 5.1.3 The Instruction Set 147


Array (PLA) 71 5.1.4 Opcodes 149
3.3.5 Logical Completeness 72 5.1.5 Data Types 149
3.4 Basic Storage Elements 73 5.1.6 Addressing Modes 150
3.4.1 The R-S Latch 73 5.1.7 Condition Codes 150
3.4.2 The Gated D Latch 74 5.2 Operate Instructions 151
3.5 The Concept of Memory 75 5.2.1 ADD, AND, and NOT 151
3.5.1 Address Space 75 5.2.2 Immediates 152
3.5.2 Addressability 76 5.2.3 The LEA Instruction (Although Not Really
3.5.3 A 22 -by-3-Bit Memory 76 an Operate) 154
3.6 Sequential Logic Circuits 78 5.3 Data Movement Instructions 155
3.6.1 A Simple Example: The 5.3.1 PC-Relative Mode 156
Combination Lock 79 5.3.2 Indirect Mode 158
3.6.2 The Concept of State 80 5.3.3 Base+offset Mode 159
3.6.3 The Finite State Machine and Its 5.3.4 An Example 160
State Diagram 82 5.4 Control Instructions 161
3.6.4 The Synchronous Finite 5.4.1 Conditional Branches 162
State Machine 85 5.4.2 Two Methods of Loop Control 165
3.6.5 The Clock 86 5.4.3 The JMP Instruction 169
3.6.6 Example: A Danger Sign 87 5.4.4 The TRAP Instruction 169
3.7 Preview of Coming Attractions: The Data Path 5.5 Another Example: Counting Occurrences
of the LC-3 93 of a Character 170
Exercises 95 5.6 The Data Path Revisited 173
5.6.1 Basic Components of the
Data Path 175
4 The von Neumann Model 121 5.6.2 The Instruction Cycle Specific
4.1 Basic Components 121 to the LC-3 176
4.1.1 Memory 122 Exercises 177
4.1.2 Processing Unit 123
4.1.3 Input and Output 124
4.1.4 Control Unit 125 6 Programming 203
4.2 The LC-3: An Example von 6.1 Problem Solving 203
Neumann Machine 125 6.1.1 Systematic Decomposition 203
4.3 Instruction Processing 127 6.1.2 The Three Constructs: Sequential,
4.3.1 The Instruction 127 Conditional, Iterative 204
4.3.2 The Instruction Cycle (NOT the 6.1.3 LC-3 Control Instructions to Implement
Clock Cycle!) 130 the Three Constructs 205
4.3.3 Changing the Sequence of 6.1.4 The Character Count Example from
Execution 132 Chapter 5, Revisited 206
4.3.4 Control of the Instruction Cycle 134 6.2 Debugging 210
4.3.5 Halting the Computer (the TRAP 6.2.1 Debugging Operations 211
Instruction) 136 6.2.2 Use of an Interactive Debugger 212
4.4 Our First Program: A Multiplication Exercises 220
Algorithm 137
Exercises 139
7 Assembly Language 231
7.1 Assembly Language Programming—Moving
5 The LC-3 145 Up a Level 231
5.1 The ISA: Overview 145 7.2 An Assembly Language Program 232
5.1.1 Memory Organization 146 7.2.1 Instructions 233
5.1.2 Registers 146 7.2.2 Pseudo-Ops (Assembler Directives) 236
Contents ix

7.2.3 Example: The Character Count Example 9.2 Input/Output 317


of Section 5.5, Revisited Again! 238 9.2.1 Some Basic Characteristics
7.3 The Assembly Process 240 of I/O 317
7.3.1 Introduction 240 9.2.2 Input from the Keyboard 320
7.3.2 A Two-Pass Process 240 9.2.3 Output to the Monitor 322
7.3.3 The First Pass: Creating the 9.2.4 A More Sophisticated Input
Symbol Table 241 Routine 325
7.3.4 The Second Pass: Generating the 9.2.5 Implementation of Memory-Mapped
Machine Language Program 242 I/O, Revisited 326
7.4 Beyond the Assembly of a Single Assembly 9.3 Operating System Service Routines
Language Program 243 (LC-3 Trap Routines) 327
7.4.1 The Executable Image 244 9.3.1 Introduction 327
7.4.2 More than One Object File 244 9.3.2 The Trap Mechanism 329
Exercises 245 9.3.3 The TRAP Instruction 330
9.3.4 The RTI Instruction: To Return
Control to the Calling
8 Data Structures 263 Program 331
8.1 Subroutines 263 9.3.5 A Summary of the Trap Service
8.1.1 The Call/Return Mechanism 265 Routine Process 331
8.1.2 JSR(R)—The Instruction That Calls 9.3.6 Trap Routines for Handling I/O 333
the Subroutine 266 9.3.7 A Trap Routine for Halting
8.1.3 Saving and Restoring Registers 267 the Computer 335
8.1.4 Library Routines 269 9.3.8 The Trap Routine for Character Input
8.2 The Stack 273 (One Last Time) 336
8.2.1 The Stack—An Abstract Data Type 273 9.3.9 PUTS: Writing a Character String to
8.2.2 Two Example Implementations 273 the Monitor 338
8.2.3 Implementation in Memory 274 9.4 Interrupts and Interrupt-Driven I/O 339
8.2.4 The Complete Picture 278 9.4.1 What Is Interrupt-Driven I/O? 339
8.3 Recursion, a Powerful Technique When Used 9.4.2 Why Have Interrupt-Driven I/O? 340
Appropriately 280 9.4.3 Two Parts to the Process 341
8.3.1 Bad Example Number 1: Factorial 280 9.4.4 Part I: Causing the Interrupt to
8.3.2 Fibonacci, an Even Worse Occur 341
Example 285 9.4.5 Part II: Handling the Interrupt
8.3.3 The Maze, a Good Example 288 Request 344
8.4 The Queue 294 9.4.6 An Example 347
8.4.1 The Basic Operations: Remove from 9.4.7 Not Just I/O Devices 349
Front, Insert at Rear 295 9.5 Polling Revisited, Now That We Know
8.4.2 Wrap-Around 295 About Interrupts 350
8.4.3 How Many Elements Can We Store 9.5.1 The Problem 350
in a Queue? 296 9.5.2 The Solution 351
8.4.4 Tests for Underflow, Overflow 297 Exercises 352
8.4.5 The Complete Story 298
8.5 Character Strings 300
Exercises 304
10 A Calculator 379
10.1 Data Type Conversion 380
9 I/O 313 10.1.1 Example: A Bogus Program:
9.1 Privilege, Priority, and the Memory 2 + 3 = e 381
Address Space 314 10.1.2 Input Data (ASCII to Binary) 381
9.1.1 Privilege and Priority 314 10.1.3 Display Result (Binary
9.1.2 Organization of Memory 316 to ASCII) 385
x Contents

10.2 Arithmetic Using a Stack 387 12.3.7 Logical Operators 438


10.2.1 The Stack as Temporary Storage 387 12.3.8 Increment /Decrement Operators 439
10.2.2 An Example 388 12.3.9 Expressions with Multiple
10.2.3 OpAdd, OpMult, and OpNeg 389 Operators 441
10.3 The Calculator 395 12.4 Problem Solving Using Operators 441
10.3.1 Functionality 395 12.5 Tying It All Together 444
10.3.2 Code 396 12.5.1 Symbol Table 444
Exercises 402 12.5.2 Allocating Space for Variables 445
12.5.3 A Comprehensive Example 447
12.6 Additional Topics 449
12.6.1 Variations of the Basic Types 450
11 Introduction to C/C++ 12.6.2 Literals, Constants, and Symbolic
Programming 405 Values 451
11.1 Our Objective 405 12.6.3 Additional C Operators 452
11.2 Bridging the Gap 406 12.7 Summary 453
11.3 Translating High-Level Language Exercises 453
Programs 410
11.3.1 Interpretation 410
11.3.2 Compilation 411 13 Control Structures 457
11.3.3 Pros and Cons 411 13.1 Introduction 457
11.4 The C/C++ Programming Languages 411 13.2 Conditional Constructs 457
11.4.1 The Origins of C and C++ 411 13.2.1 The if Statement 458
11.4.2 How We Will Approach C 13.2.2 The if-else Statement 460
and C++ 412 13.3 Iteration Constructs 464
11.4.3 The Compilation Process 413 13.3.1 The while Statement 464
11.4.4 Software Development 13.3.2 The for Statement 466
Environments 415 13.3.3 The do-while Statement 471
11.5 A Simple Example in C 415 13.4 Problem Solving Using Control
11.5.1 The Function main 415 Structures 472
11.5.2 Formatting, Comments, and Style 417 13.4.1 Problem 1: Approximating the
11.5.3 The C Preprocessor 418 Value of 𝜋 472
11.5.4 Input and Output 419 13.4.2 Problem 2: Finding Prime Numbers
11.6 Summary 422 Less Than 100 474
Exercises 422 13.4.3 Problem 3: Analyzing an E-mail
Address 477
13.5 Additional C Control Structures 480
13.5.1 The switch Statement 480
12 Variables and Operators 425 13.5.2 The break and continue
12.1 Introduction 425
Statements 482
12.2 Variables 425
13.5.3 An Example: Simple
12.2.1 Four Basic Data Types 426
Calculator 482
12.2.2 Choosing Identifiers 429
13.6 Summary 484
12.2.3 Scope: Local vs. Global 429
Exercises 484
12.2.4 More Examples 431
12.3 Operators 432
12.3.1 Expressions and Statements 433
12.3.2 The Assignment Operator 433 14 Functions 491
12.3.3 Arithmetic Operators 434 14.1 Introduction 491
12.3.4 Order of Evaluation 435 14.2 Functions in C 492
12.3.5 Bitwise Operators 436 14.2.1 A Function with a Parameter 492
12.3.6 Relational Operators 437 14.2.2 Example: Area of a Ring 495
Contents xi

14.3 Implementing Functions in C 497 16.3.6 Problem Solving: Insertion Sort 556
14.3.1 Run-Time Stack 497 16.3.7 Common Pitfalls with Arrays in C 559
14.3.2 Getting It All to Work 500 16.3.8 Variable-Length Arrays 559
14.3.3 Tying It All Together 505 16.3.9 Multidimensional Arrays in C 561
14.4 Problem Solving Using Functions 507 16.4 Summary 563
14.4.1 Problem 1: Case Conversion 507 Exercises 563
14.4.2 Problem 2: Pythagorean Triples 508
14.5 Summary 510
Exercises 511 17 Recursion 569
17.1 Introduction 569
17.2 What Is Recursion? 570
15 Testing and Debugging 517 17.3 Recursion vs. Iteration 571
15.1 Introduction 517 17.4 Towers of Hanoi 572
15.2 Types of Errors 518 17.5 Fibonacci Numbers 576
15.2.1 Syntactic Errors 519 17.6 Binary Search 581
15.2.2 Semantic Errors 519 17.7 Escaping a Maze 583
15.2.3 Algorithmic Errors 521 17.8 Summary 586
15.2.4 Specification Errors 522 Exercises 587
15.3 Testing 523
15.3.1 Black-Box Testing 524
15.3.2 White-Box Testing 524 18 I/O in C 593
15.4 Debugging 525 18.1 Introduction 593
15.4.1 Ad Hoc Techniques 526 18.2 The C Standard Library 593
15.4.2 Source-Level Debuggers 526 18.3 I/O, One Character at a Time 594
15.5 Programming for Correctness 528 18.3.1 I/O Streams 594
15.5.1 Nailing Down the Specifications 529 18.3.2 putchar 595
15.5.2 Modular Design 529 18.3.3 getchar 595
15.5.3 Defensive Programming 530 18.3.4 Buffered I/O 595
15.6 Summary 531 18.4 Formatted I/O 597
Exercises 532 18.4.1 printf 597
18.4.2 scanf 599
18.4.3 Variable Argument Lists 601
16 Pointers and Arrays 537 18.5 I/O from Files 602
16.1 Introduction 537 18.6 Summary 605
16.2 Pointers 537 Exercises 605
16.2.1 Declaring Pointer Variables 539
16.2.2 Pointer Operators 540
16.2.3 Passing a Reference Using 19 Dynamic Data Structures in C 607
Pointers 541 19.1 Introduction 607
16.2.4 Null Pointers 543 19.2 Structures 608
16.2.5 Demystifying the Syntax 543 19.2.1 typedef 610
16.2.6 An Example Problem Involving 19.2.2 Implementing Structures in C 611
Pointers 544 19.3 Arrays of Structures 611
16.3 Arrays 545 19.4 Dynamic Memory Allocation 614
16.3.1 Declaring and Using Arrays 546 19.4.1 Dynamically Sized Arrays 616
16.3.2 Examples Using Arrays 547 19.5 Linked Lists 618
16.3.3 Arrays as Parameters 550 19.5.1 Support Functions 620
16.3.4 Strings in C 552 19.5.2 Adding a Node to a Linked List 622
16.3.5 The Relationship Between Arrays and 19.5.3 Deleting Node from a Linked List 625
Pointers in C 554 19.5.4 Arrays vs. Linked Lists 626
xii Contents

19.6 Summary 628 C The Microarchitecture of


Exercises 629 the LC-3 699
C.1 Overview 699
C.2 The State Machine 701
20 Introduction to C++ 633 C.3 The Data Path 703
20.1 Essential C++ 633 C.4 The Control Structure 706
20.2 Going from C to C++ 634 C.5 The TRAP Instruction 710
20.2.1 Compiling C++ Code 634 C.6 Memory-Mapped I/O 711
20.2.2 Namespaces 636 C.7 Interrupt and Exception Control 712
20.2.3 Input and Output 636 C.7.1 Initiating an Interrupt 714
20.2.4 Pass by Reference 637 C.7.2 Returning from an Interrupt or Trap
20.2.5 Function Overloading 638 Service Routine, RTI 717
20.2.6 Dynamic Allocation 639 C.7.3 Initiating an Exception 717
20.2.7 Compilation to Machine C.8 Control Store 719
Version 639
20.3 Classes 639
20.3.1 Methods 640
20.3.2 Access Specifiers 642
20.3.3 Constructors 644 D The C Programming
20.3.4 Advanced Topics 645 Language 721
20.4 Containers and Templates 647 D.1 Overview 721
20.4.1 Vectors 647 D.2 C Conventions 721
20.4.2 Templates 649 D.2.1 Source Files 721
20.5 Summary 649 D.2.2 Header Files 721
Exercises 650 D.2.3 Comments 722
D.2.4 Literals 722
D.2.5 Formatting 724
A The LC-3 ISA 653 D.2.6 Keywords 724
A.1 Overview 653 D.3 Types 725
A.2 The Instruction Set 655 D.3.1 Basic Data Types 725
A.3 Interrupt and Exception Processing 675 D.3.2 Type Qualifiers 726
A.3.1 Interrupts 676 D.3.3 Storage Class 728
A.3.2 Exceptions 676 D.3.4 Derived Types 728
D.3.5 typedef 731
D.4 Declarations 731
B From LC-3 to x86 679 D.4.1 Variable Declarations 731
B.1 LC-3 Features and Corresponding x86 D.4.2 Function Declarations 732
Features 680 D.5 Operators 733
B.1.1 Instruction Set 680 D.5.1 Assignment Operators 733
B.1.2 Memory 685 D.5.2 Arithmetic Operators 734
B.1.3 Internal State 687 D.5.3 Bit-Wise Operators 734
B.2 The Format and Specification of D.5.4 Logical Operators 735
x86 Instructions 690 D.5.5 Relational Operators 735
B.2.1 Prefix 691 D.5.6 Increment/Decrement Operators 736
B.2.2 Opcode 691 D.5.7 Conditional Expression Operators 736
B.2.3 ModR/M Byte 692 D.5.8 Pointer, Array, and Structure
B.2.4 SIB Byte 693 Operators 737
B.2.5 Displacement 693 D.5.9 sizeof 738
B.2.6 Immediate 693 D.5.10 Order of Evaluation 738
B.3 An Example 695 D.5.11 Type Conversions 739
Contents xiii

D.6 Expressions and Statements 740 D.9 Some Standard Library Functions 747
D.6.1 Expressions 740 D.9.1 I/O Functions 747
D.6.2 Statements 740 D.9.2 String Functions 749
D.7 Control 741 D.9.3 Math Functions 750
D.7.1 If 741 D.9.4 Utility Functions 750
D.7.2 If-else 741
D.7.3 Switch 742
D.7.4 While 743 E Useful Tables 753
D.7.5 For 743 E.1 Commonly Used Numerical Prefixes 753
D.7.6 Do-while 744 E.2 Standard ASCII codes 754
D.7.7 Break 744 E.3 Powers of 2 755
D.7.8 continue 745
D.7.9 return 745
D.8 The C Preprocessor 746
D.8.1 Macro Substitution 746 F Solutions to Selected
D.8.2 File Inclusion 747 Exercises 757
Preface

Finally, the third edition! We must first thank all those who have been pushing
us to produce a third edition. Since the publication of the second edition was so
long ago, clearly the material must be out of date. Wrong! Fundamentals do not
change very often, and our intent continues to be to provide a book that explains
the fundamentals clearly in the belief that if the fundamentals are mastered, there
is no limit to how high one can soar if one’s talent and focus are equal to the task.
We must also apologize that it took so long to produce this revision. Please
know that the delay in no way reflects any lack of enthusiasm on our part. We are
both as passionate about the foundation of computing today as we were 25 years
ago when we overhauled the first course in computing that eventually became
the first edition of this book. Indeed, we have both continued to teach the course
regularly. And, as expected, each time we teach, we develop new insights as to
what to teach, new examples to explain things, and new ways to look at things.
The result of all this, hopefully, is that we have captured this in the third edition.
It is a pleasure to finally be writing this preface. We have received an enor-
mous number of comments from students who have studied the material in the
book and from instructors who have taught from it. It is gratifying to know that
a lot of people agree with our approach, and that this agreement is based on real
firsthand experience learning from it (in the case of students) and watching stu-
dents learn from it (in the case of instructors). The excitement displayed in their
correspondence continues to motivate us.

Why the Book Happened


This textbook evolved from EECS 100, the first computing course for computer
science, computer engineering, and electrical engineering majors at the Univer-
sity of Michigan, Ann Arbor, that Kevin Compton and the first author introduced
for the first time in the fall term, 1995.
EECS 100 happened at Michigan because Computer Science and Engi-
neering faculty had been dissatisfied for many years with the lack of student
comprehension of some very basic concepts. For example, students had a lot
of trouble with pointer variables. Recursion seemed to be “magic,” beyond
understanding.
We decided in 1993 that the conventional wisdom of starting with a high-
level programming language, which was the way we (and most universities) were
xvi Preface

doing it, had its shortcomings. We decided that the reason students were not get-
ting it was that they were forced to memorize technical details when they did not
understand the basic underpinnings.
Our result was the bottom-up approach taken in this book, where we contin-
ually build on what the student already knows, only memorizing when absolutely
necessary. We did not endorse then and we do not endorse now the popular
information hiding approach when it comes to learning. Information hiding is a
useful productivity enhancement technique after one understands what is going on.
But until one gets to that point, we insist that information hiding gets in the way of
understanding. Thus, we continually build on what has gone before so that nothing
is magic and everything can be tied to the foundation that has already been laid.
We should point out that we do not disagree with the notion of top-down
design. On the contrary, we believe strongly that top-down design is correct
design. But there is a clear difference between how one approaches a design prob-
lem (after one understands the underlying building blocks) and what it takes to get
to the point where one does understand the building blocks. In short, we believe
in top-down design, but bottom-up learning for understanding.

Major Changes in the Third Edition


The LC-3
A hallmark of our book continues to be the LC-3 ISA, which is small enough to
be described in a few pages and hopefully mastered in a very short time, yet rich
enough to convey the essence of what an ISA provides. It is the LC “3” because
it took us three tries to get it right. Four tries, actually, but the two changes in the
LC-3 ISA since the second edition (i.e., changes to the LEA instruction and to the
TRAP instruction) are so minor that we decided not to call the slightly modified
ISA the LC-4.
The LEA instruction no longer sets condition codes. It used to set condition
codes on the mistaken belief that since LEA stands for Load Effective Address,
it should set condition codes like LD, LDI, and LDR do. We recognize now that
this reason was silly. LD, LDI, and LDR load a register from memory, and so
the condition codes provide useful information – whether the value loaded is
negative, zero, or positive. LEA loads an address into a register, and for that, the
condition codes do not really provide any value. Legacy code written before this
change should still run correctly.
The TRAP instruction no longer stores the linkage back to the calling pro-
gram in R7. Instead, the PC and PSR are pushed onto the system stack and popped
by the RTI instruction (renamed Return from Trap or Interrupt) as the last instruc-
tion in a trap routine. Trap routines now execute in privileged memory (x0000 to
x2FFF). This change allows trap routines to be re-entrant. It does not affect old
code provided the starting address of the trap service routines, obtained from the
Trap Vector Table, is in privileged memory and the terminating instruction of
each trap service routine is changed from RET to RTI.
As before, Appendix A specifies the LC-3 completely.
Preface xvii

The Addition of C++


We’ve had an ongoing debate about how to extend our approach and textbook
to C++. One of the concerns about C++ is that many of its language features
are too far abstracted from the underlying layers to make for an easy fit to our
approach. Another concern is that C++ is such a vast language that any adequate
coverage would require an additional thousand pages. We also didn’t want to drop
C completely, as it serves as a de facto development language for systems and
hardware-oriented projects.
We adopted an approach where we cover the common core of C and C++
from Chapters 11 through 19. This common core is similar to what was covered
in the second edition, with some minor updates. Chapter 20 serves as a transition,
which we aspired to make very smooth, to the core concepts of C++. With this
approach, we get to explore the evolution between C and C++, which serves as
a key learning opportunity on what changes were essential to boost programmer
productivity.
In particular, we focus on classes in C++ as an evolution from structures in
C. We discuss classes as a compiler construct, how method calls are made, and
the notion of constructors. We touch upon inheritance, too, but leave the details
for subsequent treatment in follow-on courses.
An important element of C++ is the introduction of container classes in the
Standard Template Library, which is a heavily utilized part of the C++ language.
This provides an opportunity to dive deep into the vector class, which serves as
a continuation of a running example in the second half around the support for
variable-sized arrays in high-level languages, or in particular, C’s lack of support
for them.

Other Important Updates


Although no chapter in the book has remained untouched, some chapters have
been changed more than others. In Chapter 2, we expanded the coverage of the
floating point data type and the conversion of fractions between decimal and
binary numbers in response to several instructors who wanted them. We moved
DeMorgan’s Laws from Chapter 3 to Chapter 2 because the concept is really about
AND and OR functions and not about digital logic implementation. In Chap-
ter 3, we completely overhauled the description of state, latches, flip-flops, finite
state machines, and our example of a danger sign. We felt the explanations in the
second edition were not as clear as they needed to be, and the concepts are too
important to not get right. We revised Chapter 4 to better introduce the LC-3,
including a different set of instructions, leading to our first complete example of
a computer program.
Our organization of Chapters 8, 9, and 10 was completely overhauled in order
to present essentially the same material in a more understandable way. Although
most of our treatment of data structures waits until we have introduced C in the
second half of the book, we felt it was important to introduce stacks, queues,
and character strings as soon as the students have moved out of programming in
machine language so they can write programs dealing with these data structures
xviii Preface

and see how these structures are actually organized in memory. We moved our dis-
cussion of subroutines up to Chapter 8 because of their importance in constructing
richer programs.
We also introduced recursion in Chapter 8, although its main treatment is still
left for the second half of the book. Both the expressive power of recursion and
its misuse are so common in undergraduate curricula that we felt dealing with
it twice, first while they are engrossed in the bowels of assembly language and
again after moving up to the richness of C, was worthwhile.
Chapter 9 now covers all aspects of I/O in one place, including polling and
interrupt-driven I/O. Although the concept of privilege is present in the second
edition, we have put greater emphasis on it in the third edition. Our coverage
of system calls (the trap routines invoked by the TRAP instruction) appears in
Chapter 9. All of the above reduce Chapter 10 to simply a comprehensive example
that pulls together a lot of the first half of the book: the simulation of a calculator.
Doing so requires 12 subroutines that are laid out in complete detail. Two con-
cepts that are needed to make this happen are stack arithmetic and ASCII/binary
conversion, so they are included in Chapter 10.
We reworked all the examples in Chapters 11 through 19 to use the latest
ANSI Standard C or C18. We also added more coding examples to further empha-
size points and to provide clarity on complex topics such as pointers, arrays,
recursion, and pointers to pointers in C. In Chapter 16, we added additional
sections on variable-sized arrays in C, and on multidimensional arrays.

Chapter Organization
The book breaks down into two major segments, (a) the underlying structure
of a computer, as manifested in the LC-3; and (b) programming in a high-level
language, in our case C and C++.

The LC-3
We start with the underpinnings that are needed to understand the workings of a
real computer. Chapter 2 introduces the bit and arithmetic and logical operations
on bits. Then we begin to build the structure needed to understand the LC-3.
Chapter 3 takes the student from an MOS transistor, step by step, to a “real”
memory and a finite state machine.
Our real memory consists of four words of three bits each, rather than
16 gigabytes, which is common in most laptops today. Its description fits on a
single page (Figure 3.20), making it easy for a student to grasp. By the time stu-
dents get there, they have been exposed to all the elements needed to construct the
memory. The finite state machine is needed to understand how a computer pro-
cesses instructions, starting in Chapter 4. Chapter 4 introduces the von Neumann
execution model and enough LC-3 instructions to allow an LC-3 program to be
written. Chapter 5 introduces most of the rest of the LC-3 ISA.
Preface xix

The LC-3 is a 16-bit architecture that includes physical I/O via keyboard
and monitor, TRAPs to the operating system for handling service calls, con-
ditional branches on (N, Z, and P) condition codes, a subroutine call/return
mechanism, a minimal set of operate instructions (ADD, AND, and NOT), and
various addressing modes for loads and stores (direct, indirect, Base+offset).
Chapter 6 is devoted to programming methodology (stepwise refinement)
and debugging, and Chapter 7 is an introduction to assembly language program-
ming. We have developed a simulator and an assembler for the LC-3 that runs on
Windows, Linux, and Mac0S platforms. It can be downloaded from the web at
no charge.
Students use the simulator to test and debug programs written in LC-3
machine language and in LC-3 assembly language. The simulator allows online
debugging (deposit, examine, single-step, set breakpoint, and so on). The sim-
ulator can be used for simple LC-3 machine language and assembly language
programming assignments, which are essential for students to master the concepts
presented throughout the first ten chapters.
Assembly language is taught, but not to train expert assembly language pro-
grammers. Indeed, if the purpose was to train assembly language programmers,
the material would be presented in an upper-level course, not in an introductory
course for freshmen. Rather, the material is presented in Chapter 7 because it
is consistent with the paradigm of the book. In our bottom-up approach, by the
time the student reaches Chapter 7, he/she can handle the process of transform-
ing assembly language programs to sequences of 0s and 1s. We go through the
process of assembly step by step for a very simple LC-3 Assembler. By hand
assembling, the student (at a very small additional cost in time) reinforces the
important fundamental concept of translation.
It is also the case that assembly language provides a user-friendly notation
to describe machine instructions, something that is particularly useful for writing
programs in Chapters 8, 9, and 10, and for providing many of the explanations in
the second half of the book. Starting in Chapter 11, when we teach the semantics
of C statements, it is far easier for the reader to deal with ADD R1, R2, R3 than
to have to struggle with 0001001010000011.
Chapter 8 introduces three important data structures: the stack, the queue,
and the character string, and shows how they are stored in memory. The sub-
routine call/return mechanism of the LC-3 is presented because of its usefulness
both in manipulating these data structures and in writing programs. We also intro-
duce recursion, a powerful construct that we revisit much more thoroughly in the
second half of the book (in Chapter 17), after the student has acquired a much
stronger capability in high-level language programming. We introduce recursion
here to show by means of a few examples the execution-time tradeoffs incurred
with recursion as a first step in understanding when its use makes sense and when
it doesn’t.
Chapter 9 deals with input/output and some basic interaction between the
processor and the operating system. We introduce the notions of priority and
privilege, which are central to a systems environment. Our treatment of I/O is
all physical, using keyboard data and status registers for input and display data
and status registers for output. We describe both interrupt-driven I/O and I/O
xx Preface

under program control. Both are supported by our LC-3 simulator so the student
can write interrupt drivers. Finally, we show the actual LC-3 code of the trap ser-
vice routines that the student has invoked with the TRAP instruction starting in
Chapter 4. To handle interrupt-driven I/O and trap service routines, we complete
the description of the LC-3 ISA with details of the operation of the Return from
Trap or Interrupt (RTI) and TRAP instructions.
The first half of the book concludes with Chapter 10, a comprehensive exam-
ple of a simple calculator that pulls together a lot of what the students have learned
in Chapters 1 through 9.

Programming in C and C++


By the time the student gets to the second part of the textbook, he/she has an
understanding of the layers below. In our coverage of programming in C and
C++, we leverage this foundation by showing the resulting LC-3 code generated
by a compiler with each new concept in C/C++.
We start with the C language because it provides the common, essential
core with C++. The C programming language fits very nicely with our bottom-
up approach. Its low-level nature allows students to see clearly the connection
between software and the underlying hardware. In this book, we focus on basic
concepts such as control structures, functions, and arrays. Once basic program-
ming concepts are mastered, it is a short step for students to learn more advanced
concepts such as objects and abstraction in C++.
Each time a new high-level construct is introduced, the student is shown
the LC-3 code that a compiler would produce. We cover the basic constructs of
C (variables, operators, control, and functions), pointers, arrays, recursion, I/O,
complex data structures, and dynamic allocation. With C++, we cover some basic
improvements over C, classes, and containers.
Chapter 11 is a gentle introduction to high-level programming languages. At
this point, students have dealt heavily with assembly language and can understand
the motivation behind what high-level programming languages provide. Chapter
11 also contains a simple C program, which we use to kick-start the process of
learning C.
Chapter 12 deals with values, variables, constants, and operators. Chapter 13
introduces C control structures. We provide many complete program examples
to give students a sample of how each of these concepts is used in practice. LC-3
code is used to demonstrate how each C construct affects the machine at the lower
levels.
Chapter 14 introduces functions in C. Students are not merely exposed to the
syntax of functions. Rather they learn how functions are actually executed, with
argument-passing using a run-time stack. A number of examples are provided.
In Chapter 15, students are exposed to techniques for testing their code, along
with debugging high-level source code. The ideas of white-box and black-box
testing are discussed.
Chapter 16 teaches pointers and arrays, relying heavily on the student’s
understanding of how memory is organized. We discuss C’s notions of fixed size
and variable-length arrays, along with multidimensional array allocation.
Preface xxi

Chapter 17 teaches recursion, using the student’s newly gained knowledge of


functions, stack frames, and the run-time stack. Chapter 18 introduces the details
of I/O functions in C, in particular, streams, variable length argument lists, and
how C I/O is affected by the various format specifications. This chapter relies on
the student’s earlier exposure to physical I/O in Chapter 8. Chapter 19 discusses
structures in C, dynamic memory allocation, and linked lists.
Chapter 20 provides a jump-start on C++ programming by discussing its
roots in C and introducing the idea of classes as a natural evolution from struc-
tures. We also cover the idea of containers in the standard template library, to
enable students to quickly jump into productive programming with C++.
Along the way, we have tried to emphasize good programming style and cod-
ing methodology by means of examples. Novice programmers probably learn at
least as much from the programming examples they read as from the rules they
are forced to study. Insights that accompany these examples are highlighted by
means of lightbulb icons that are included in the margins.
We have found that the concept of pointer variables (Chapter 16) is not at all
a problem. By the time students encounter it, they have a good understanding of
what memory is all about, since they have analyzed the logic design of a small
memory (Chapter 3). They know the difference, for example, between a memory
location’s address and the data stored there.
Recursion ceases to be magic since, by the time a student gets to that point
(Chapter 17), he/she has already encountered all the underpinnings. Students
understand how stacks work at the machine level (Chapter 8), and they understand
the call/return mechanism from their LC-3 machine language programming expe-
rience, and the need for linkages between a called program and the return to the
caller (Chapter 8). From this foundation, it is not a large step to explain functions
by introducing run-time stack frames (Chapter 14), with a lot of the mystery about
argument passing, dynamic declarations, and so on, going away. Since a function
can call a function, it is one additional small step (certainly no magic involved)
for a function to call itself.

The Simulator/Debugger
The importance of the Simulator/Debugger for testing the programs a student
writes cannot be overemphasized. We believe strongly that there is no substi-
tute for hands-on practice testing one’s knowledge. It is incredibly fulfilling
to a student’s education to write a program that does not work, testing it to
find out why it does not work, fixing the bugs himself/herself, and then see-
ing the program run correctly. To that end, the Simulator/Debugger has been
completely rewritten. It runs on Windows, Linux, and MacOS while present-
ing the same user interface (GUI) regardless of which platform the student is
using. We have improved our incorporation of interrupt-driven I/O into the Sim-
ulator’s functionality so students can easily write interrupt drivers and invoke
them by interrupting a lower priority executing program. ...in their first course in
computing!
xxii Preface

Alternate Uses of the Book


We wrote the book as a textbook for a freshman introduction to computing. We
strongly believe that our motivated bottom-up approach is the best way for stu-
dents to learn the fundamentals of computing. We have seen lots of evidence
showing that in general, students who understand the fundamentals of how the
computer works are better able to grasp the stuff that they encounter later, includ-
ing the high-level programming languages that they must work in, and that they
can learn the rules of these programming languages with far less memorizing
because everything makes sense. For us, the best use of the book is a one-semester
freshman course for particularly motivated students, or a two-semester sequence
where the pace is tempered.
Having said that, we recognize that others see the curriculum differently.
Thus, we hasten to add that the book can certainly be used effectively in other
ways. In fact, each of the following has been tried, and all have been used
successfully:
Two Quarters, Freshman Course
An excellent use of the book. No prerequisites, the entire book can be covered
easily in two quarters, the first quarter for Chapters 1–10, the second quarter for
Chapters 11–20. The pace is brisk, but the entire book can be covered easily in
two academic quarters.
One-Semester, Second Course
Several schools have successfully used the book in their second course,
after the students have been exposed to programming with an object-oriented
programming language in a milder first course. The rationale is that after expo-
sure to high-level language programming in the first course, the second course
should treat at an introductory level digital logic, basic computer organization,
and assembly language programming. The first two-thirds of the semester is spent
on Chapters 1–10, and the last third on Chapters 11–20, teaching C programming,
but also showing how some of the magic from the students’ first course can be
implemented. Coverage of functions, activation records, recursion, pointer vari-
ables, and data structures are examples of topics where getting past the magic is
particularly useful. The second half of the book can move more quickly since the
student has already taken an introductory programming course. This model also
allows students who were introduced to programming with an object-oriented
language to pick up C, which they will almost certainly need in some of their
advanced software courses.
A Sophomore-Level Computer Organization Course
The book has been used to delve deeply into computer implementation in
the sophomore year. The semester is spent in Chapters 1 through 10, often
culminating in a thorough study of Appendix C, which provides the complete
microarchitecture of a microprogrammed LC-3. We note, however, that some
very important ideas in computer architecture are not covered in the book, most
notably cache memory, pipelining, and virtual memory. Instructors using the
book this way are encouraged to provide extra handouts dealing with those top-
ics. We agree that they are very important to the student’s computer architecture
Preface xxiii

education, but we feel they are better suited to a later course in computer
architecture and design. This book is not intended for that purpose.

Why LC-3, and Not ARM or RISCV?


We have been asked why we invented the LC-3 ISA, rather than going with ARM,
which seems to be the ISA of choice for most mobile devices, or RISCV, which
has attracted substantial interest over the last few years.
There are many reasons. First, we knew that the ISA we selected would
be the student’s first ISA, not his/her last ISA. Between the freshman year and
graduation, the student is likely to encounter several ISAs, most of which are in
commercial products: ARM, RISCV, x86, and POWER, to name a few.
But all the commercial ISAs have details that have no place in an introductory
course but still have to be understood for the student to use them effectively. We
could, of course, have subset an existing ISA, but that always ends up in questions
of what to take out and what to leave in with a result that is not as clean as one
would think at first blush. Certainly not as clean as what one can get when starting
from scratch. It also creates an issue whenever the student uses an instruction in
an exam or on an assignment that is not in the subset. Not very clean from a
pedagogical sense.
We wanted an ISA that was clean with no special cases to deal with, with as
few opcodes as necessary so the student could spend almost all his/her time on
the fundamental concepts in the course and very little time on the nuances of the
instruction set. The formats of all instructions in the LC-3 fit on a single page.
Appendix A provides all the details (i.e., the complete data sheet) of the entire
LC-3 ISA in 25 pages.
We also wanted an instruction set that in addition to containing only a few
instructions was very rich in the breadth of what it embraced. So, we came up
with the LC-3, an instruction set with only 15 four-bit opcodes, a small enough
number that students can absorb the ISA without even trying. For arithmetic, we
have only ADD instead of ADD, SUB, MUL, and DIV. For logical operations,
we have AND and NOT, foregoing OR, XOR, etc. We have no shift or rotate
instructions. In all these cases, the missing opcodes can be implemented with
procedures using the few opcodes that the LC-3 provides. We have loads and
stores with three different addressing modes, each addressing mode useful for a
different purpose. We have conditional branches, subroutine calls, return from
trap or interrupt, and system calls (the TRAP instruction).
In fact, this sparse set of opcodes is a feature! It drives home the need for
creating more complex functionality out of simple operations, and the need for
abstraction, both of which are core concepts in the book.
Most importantly, we have found from discussions with hundreds of students
that starting with the LC-3 does not put them at a disadvantage in later courses.
On the contrary: For example, at one campus students were introduced to ARM in
the follow-on course, while at another campus, students were introduced to x86.
xxiv Preface

In both cases, students appreciated starting with the LC-3, and their subsequent
introduction to ARM or x86 was much easier as a result of their first learning the
fundamental concepts with the LC-3.

A Few Observations
Having now taught the course more than 20 times between us, we note the
following:

Understanding, Not Memorizing


Since the course builds from the bottom up, we have found that less memorization
of seemingly arbitrary rules is required than in traditional programming courses.
Students understand that the rules make sense since by the time a topic is taught,
they have an awareness of how that topic is implemented at the levels below
it. This approach is good preparation for later courses in design, where under-
standing of and insights gained from fundamental underpinnings are essential to
making the required design tradeoffs.

The Student Debugs the Student’s Program


We hear complaints from industry all the time about CS graduates not being able
to program. Part of the problem is the helpful teaching assistant, who contributes
far too much of the intellectual content of the student’s program so the student
never has to really master the art. Our approach is to push the student to do the
job without the teaching assistant (TA). Part of this comes from the bottom-up
approach, where memorizing is minimized and the student builds on what he/she
already knows. Part of this is the simulator, which the student uses from the day
he/she writes his/her first program. The student is taught debugging from his/her
first program and is required from the very beginning to use the debugging tools
of the simulator to get his/her programs to work. The combination of the simulator
and the order in which the subject material is taught results in students actually
debugging their own programs instead of taking their programs to the TA for
help ... with the too-frequent result that the TAs end up writing the programs for
the students.

Preparation for the Future: Cutting Through Protective Layers


Professionals who use computers in systems today but remain ignorant of what
is going on underneath are likely to discover the hard way that the effectiveness
of their solutions is impacted adversely by things other than the actual programs
they write. This is true for the sophisticated computer programmer as well as the
sophisticated engineer.
Serious programmers will write more efficient code if they understand what
is going on beyond the statements in their high-level language. Engineers, and not
just computer engineers, are having to interact with their computer systems today
Preface xxv

more and more at the device or pin level. In systems where the computer is being
used to sample data from some metering device such as a weather meter or feed-
back control system, the engineer needs to know more than just how to program
in MATLAB. This is true of mechanical, chemical, and aeronautical engineers
today, not just electrical engineers. Consequently, the high-level programming
language course, where the compiler protects the student from everything “ugly”
underneath, does not serve most engineering students well, and it certainly does
not prepare them for the future.

Rippling Effects Through the Curriculum


The material of this text clearly has a rippling effect on what can be taught in
subsequent courses. Subsequent programming courses can not only assume the
students know the syntax of C/C++ but also understand how it relates to the
underlying architecture. Consequently, the focus can be on problem solving and
more sophisticated data structures. On the hardware side, a similar effect is seen
in courses in digital logic design and in computer organization. Students start the
logic design course with an appreciation of what the logic circuits they master are
good for. In the computer organization course, the starting point is much further
along than when students are seeing the term Program Counter for the first time.
Faculty members who have taught the follow-on courses have noticed substan-
tial improvement in students’ comprehension compared to what they saw before
students took our course.

Acknowledgments
It’s been 15 years since the second edition came out, and about 20 years since we
first put together a course pack of notes that eventually morphed into the first edi-
tion. Through those years, a good number of people have jumped in, volunteered
help, adopted the book, read through drafts, suggested improvements, and so on.
We could easily fill many pages if we listed all their names. We are indebted to
each of them, and we deeply appreciate their contributions.
Still, there are some folks we feel compelled to acknowledge here, and we
apologize to all those who have helped immeasurably, but are not mentioned here
due to space limitations.
First, Professor Kevin Compton. Kevin believed in the concept of the book
since it was first introduced at a curriculum committee meeting that he chaired at
Michigan in 1993. Kevin co-taught the course at Michigan the first four times it
was offered, in 1995–1997. His insights into programming methodology (inde-
pendent of the syntax of the particular language) provided a sound foundation for
the beginning student. The course at Michigan and this book would be a lot less
were it not for Kevin’s influence.
Several colleagues and students were our major go-to guys when it came
to advice, and insights, on the current version of the book and its future.
Wen-mei Hwu, Veynu Narasiman, Steve Lumetta, Matt Frank, Faruk Guvinilir,
xxvi Preface

Chirag Sakuja, Siavash Zanganeh, Stephen Pruett, Jim Goodman, and Soner
Onder have been particularly important to us since the second edition.
McGraw-Hill has been an important partner in this undertaking, starting with
Betsy Jones, our first editor. We sent the manuscript of our first edition to several
publishers and were delighted with the many positive responses. Nonetheless, one
editor stood out. Betsy immediately checked us out, and once she was satisfied,
she became a strong believer in what we were trying to accomplish. Throughout
the process of the first two editions, her commitment and energy, as well as that
of Michelle Flomenhoft, our first development editor, were greatly appreciated.
Fifteen years is a long time between editions, and with it have come a whole new
collection of folks from McGraw-Hill that we have recently been privileged to
work with, especially Dr. Thomas Scaife, Suzy Bainbridge, Heather Ervolino,
and Jeni McAtee.
Our book has benefited from extensive comments by faculty members from
many universities. Some were in formal reviews of the manuscript, others in
e-mails or conversations at technical conferences. We gratefully acknowledge
input from Professors Jim Goodman, Wisconsin and Aukland; Soner Onder,
Michigan Tech; Vijay Pai, Purdue; Richard Johnson, Western New Mexico; Tore
Larsen, Tromso; Greg Byrd, NC State; Walid Najjar, UC Riverside; Sean Joyce,
Heidelberg College; James Boettler, South Carolina State; Steven Zeltmann,
Arkansas; Mike McGregor, Alberta; David Lilja, Minnesota; Eric Thompson,
Colorado, Denver; Brad Hutchings, Brigham Young; Carl D. Crane III, Florida;
Nat Davis, Virginia Tech; Renee Elio, University of Alberta; Kelly Flangan,
BYU; George Friedman, UIUC; Franco Fummi, Universita di Verona; Dale
Grit, Colorado State; Thor Guisrud, Stavanger College; Dave Kaeli, North-
eastern; Rasool Kenarangui, UT, Arlington; Joel Kraft, Case Western Reserve;
Wei-Ming Lin, UT, San Antonio; Roderick Loss, Montgomery College; Ron
Meleshko, Grant MacEwan Community College; Andreas Moshovos, Toronto;
Tom Murphy, The Citadel; Murali Narayanan, Kansas State; Carla Purdy, Cincin-
nati; T. N. Rajashekhara, Camden County College; Nello Scarabottolo, Universita
degli Studi di Milano; Robert Schaefer, Daniel Webster College; Tage Stabell-
Kuloe, University of Tromsoe; Jean-Pierre Steger, Burgdorf School of Engi-
neering; Bill Sverdlik, Eastern Michigan; John Trono, St. Michael’s College;
Murali Varansi, University of South Florida; Montanez Wade, Tennessee State;
Carl Wick, US Naval Academy; Robert Crisp, Arkansas; Allen Tannenbaum,
Georgia Tech; Nickolas Jovanovic, Arkansas–Little Rock; Dean Brock, North
Carolina–Asheville; Amar Raheja, Cal State–Pomona; Dayton Clark, Brooklyn
College; William Yurcik, Illinois State; Jose Delgado-Frias, Washington State;
Peter Drexel, Plymouth State; Mahmoud Manzoul, Jackson State; Dan Con-
nors, Colorado; Massoud Ghyam, USC; John Gray, UMass–Dartmouth; John
Hamilton, Auburn; Alan Rosenthal, Toronto; and Ron Taylor, Wright State.
We have continually been blessed with enthusiastic, knowledgeable, and car-
ing TAs who regularly challenge us and provide useful insights into helping us
explain things better. Again, the list is too long – more than 100 at this point.
Almost all were very good; still, we want to mention a few who were particularly
helpful. Stephen Pruett, Siavash Zangeneh, Meiling Tang, Ali Fakhrzadehgan,
Sabee Grewal, William Hoenig, Matthew Normyle, Ben Lin, Ameya Chaudhari,
Preface xxvii

Nikhil Garg, Lauren Guckert, Jack Koenig, Saijel Mokashi, Sruti Nuthalapati,
Faruk Guvenilir, Milad Hashemi, Aater Suleman, Chang Joo Lee, Bhargavi
Narayanasetty, RJ Harden, Veynu Narasiman, Eiman Ebrahimi, Khubaib, Allison
Korczynski, Pratyusha Nidamaluri, Christopher Wiley, Cameron Davison, Lisa
de la Fuente, Phillip Duran, Jose Joao, Rustam Miftakhutdinov, Nady Obeid,
Linda Bigelow, Jeremy Carillo, Aamir Hasan, Basit Sheik, Erik Johnson, Tsung-
Wei Huang, Matthew Potok, Chun-Xun Lin, Jianxiong Gao, Danny Kim, and
Iou-Jen Liu.
Several former students, former colleagues, and friends reviewed chapters in
the book. We particularly wish to thank Rich Belgard, Alba Cristina de Melo,
Chirag Sakhuja, Sabee Grewal, Pradip Bose, and Carlos Villavieja for their
help doing this. Their insights have made a much more readable version of the
material.
We have been delighted by the enthusiastic response of our colleagues at
both The University of Texas at Austin and the University of Illinois, Urbana-
Champaign, who have taught from the book and shared their insights with us:
Derek Chiou, Jacob Abraham, Ramesh Yerraballi, Nina Telang, and Aater Sule-
man at Texas, and Yuting Chen, Sayan Mitra, Volodymyr Kindratenko, Yih-Chun
Hu, Seth Hutchinson, Steve Lumetta, Juan Jaramillo, Pratik Lahiri, and Wen-mei
Hwu at Illinois. Thank you.
Also, there are those who have contributed in many different and often unique
ways. Space dictates that we leave out the detail and simply list them and say
thank you. Amanda, Bryan, and Carissa Hwu, Mateo Valero, Rich Belgard, Aman
Aulakh, Minh Do, Milena Milenkovic, Steve Lumetta, Brian Evans, Jon Valvano,
Susan Kornfield, Ed DeFranco, Evan Gsell, Tom Conte, Dave Nagle, Bruce
Shriver, Bill Sayle, Dharma Agarwal, David Lilja, Michelle Chapman.
Finally, if you will indulge the first author a bit: This book is about developing
a strong foundation in the fundamentals with the fervent belief that once that is
accomplished, students can go as far as their talent and energy can take them.
This objective was instilled in me by the professor who taught me how to be a
professor, Professor William K. Linvill. It has been more than 50 years since I
was in his classroom, but I still treasure the example he set.

A Final Word
We are hopeful that you will enjoy teaching or studying from this third edition of
our book. However, as we said in the prefaces to both previous editions, we are
mindful that the current version of the book will always be a work in progress,
and both of us welcome your comments on any aspect of it. You can reach us by
email at patt@ece.utexas.edu and sjp@illinois.edu. We hope you will.
Yale N. Patt
Sanjay J. Patel
September, 2019
CHAPTER

1 Welcome Aboard

1.1 What We Will Try to Do


Welcome to From Bits and Gates to C and Beyond. Our intent is to introduce
you over the next xxx pages to the world of computing. As we do so, we have
one objective above all others: to show you very clearly that there is no magic to
computing. The computer is a deterministic system—every time we hit it over the
head in the same way and in the same place (provided, of course, it was in the same
starting condition), we get the same response. The computer is not an electronic
genius; on the contrary, if anything, it is an electronic idiot, doing exactly what
we tell it to do. It has no mind of its own.
What appears to be a very complex organism is really just a very large, sys-
tematically interconnected collection of very simple parts. Our job throughout
this book is to introduce you to those very simple parts and, step-by-step, build the
interconnected structure that you know by the name computer. Like a house, we
will start at the bottom, construct the foundation first, and then go on to add layer
after layer, as we get closer and closer to what most people know as a full-blown
computer. Each time we add a layer, we will explain what we are doing, tying the
new ideas to the underlying fabric. Our goal is that when we are done, you will be
able to write programs in a computer language such as C using the sophisticated
features of that language and to understand what is going on underneath, inside
the computer.

1.2 How We Will Get There


We will start (in Chapter 2) by first showing that any information processed by
the computer is represented by a sequence of 0s and 1s. That is, we will encode
all information as sequences of 0s and 1s. For example, one encoding of the letter
a that is commonly used is the sequence 01100001. One encoding of the decimal
number 35 is the sequence 00100011. We will see how to perform operations on
such encoded information.
2 chapter 1 Welcome Aboard

Once we are comfortable with information represented as codes made up of


0s and 1s and operations (addition, for example) being performed on these repre-
sentations, we will begin the process of showing how a computer works. Starting
in Chapter 3, we will note that the computer is a piece of electronic equipment
and, as such, consists of electronic parts operated by voltages and interconnected
by wires. Every wire in the computer, at every moment in time, is at either a high
voltage or a low voltage. For our representation of 0s and 1s, we do not specify
exactly how high. We only care whether there is or is not a large enough voltage
relative to 0 volts to identify it as a 1. That is, the absence or presence of a rea-
sonable voltage relative to 0 volts is what determines whether it represents the
value 0 or the value 1.
In Chapter 3, we will see how the transistors that make up today’s micro-
processor (the heart of the modern computer) work. We will further see how
those transistors are combined into larger structures that perform operations,
such as addition, and into structures that allow us to save information for later
use. In Chapter 4, we will combine these larger structures into the von Neumann
machine, a basic model that describes how a computer works. We will also begin
to study a simple computer, the LC-3. We will continue our study of the LC-3 in
Chapter 5. LC-3 stands for Little Computer 3. We actually started with LC-1 but
needed two more shots at it before (we think) we got it right! The LC-3 has all
the important characteristics of the microprocessors that you may have already
heard of, for example, the Intel 8088, which was used in the first IBM PCs back
in 1981. Or the Motorola 68000, which was used in the Macintosh, vintage 1984.
Or the Pentium IV, one of the high-performance microprocessors of choice for
the PC in the year 2003. Or today’s laptop and desktop microprocessors, the Intel
Core processors – I3, I5, and I7. Or even the ARM microprocessors that are used
in most smartphones today. That is, the LC-3 has all the important characteristics
of these “real” microprocessors without being so complicated that it gets in the
way of your understanding.
Once we understand how the LC-3 works, the next step is to program it, first
in its own language (Chapter 5 and Chapter 6), and then in a language called
assembly language that is a little bit easier for humans to work with (Chap-
ter 7). Chapter 8 introduces representations of information more complex than a
simple number – stacks, queues, and character strings, and shows how to imple-
ment them. Chapter 9 deals with the problem of getting information into (input)
and out of (output) the LC-3. Chapter 9 also deals with services provided to a
computer user by the operating system. We conclude the first half of the book
(Chapter 10) with an extensive example, the simulation of a calculator, an app on
most smartphones today.
In the second half of the book (Chapters 11–20), we turn our attention
to high-level programming concepts, which we introduce via the C and C++
programming languages. High-level languages enable programmers to more
effectively develop complex software by abstracting away the details of the under-
lying hardware. C and C++ in particular offer a rich set of programmer-friendly
constructs, but they are close enough to the hardware that we can examine
how code is transformed to execute on the layers below. Our goal is to enable
you to write short, simple programs using the core parts of these programming
1.3 Two Recurring Themes 3

languages, all the while being able to comprehend the transformations required
for your code to execute on the underlying hardware.
We’ll start with basic topics in C such as variables and operators (Chapter 12),
control structures (Chapter 13), and functions (Chapter 14). We’ll see that these are
straightforward extensions of concepts introduced in the first half of the textbook.
We then move on to programming concepts in Chapters 15–19 that will enable
us to create more powerful pieces of code: Testing and Debugging (Chapter 15),
Pointers and Arrays in C (Chapter 16), Recursion (Chapter 17), Input and Output in
C (Chapter 18), and Data Structures in C (Chapter 19).
Chapters 20 is devoted to C++, which we present as an evolution of the
C programming language. Because the C++ language was initially defined as
a superset of C, many of the concepts covered in Chapters 11–19 directly map
onto the C++ language. We will introduce some of the core notions in C++ that
have helped establish C++ as one of the most popular languages for developing
real-world software. Chapter 20 is our Introduction to C++.
In almost all cases, we try to tie high-level C and C++ constructs to the
underlying LC-3 so that you will understand what you demand of the computer
when you use a particular construct in a C or C++ program.

1.3 Two Recurring Themes


Two themes permeate this book that we as professors previously took for granted,
assuming that everyone recognized their value and regularly emphasized them
to students of engineering and computer science. However, it has become clear
to us that from the git-go, we need to make these points explicit. So, we state
them here up front. The two themes are (a) the notion of abstraction and (b) the
importance of not separating in your mind the notions of hardware and software.
Their value to your development as an effective engineer or computer scien-
tist goes well beyond your understanding of how a computer works and how to
program it.
The notion of abstraction is central to all that you will learn and expect to
use in practicing your craft, whether it be in mathematics, physics, any aspect of
engineering, or business. It is hard to think of any body of knowledge where the
notion of abstraction is not critical.
The misguided hardware/software separation is directly related to your
continuing study of computers and your work with them.
We will discuss each in turn.

1.3.1 The Notion of Abstraction


The use of abstraction is all around us. When we get in a taxi and tell the driver,
“Take me to the airport,” we are using abstraction. If we had to, we could probably
direct the driver each step of the way: “Go down this street ten blocks, and make
a left turn.” And, when the driver got there, “Now take this street five blocks and
make a right turn.” And on and on. You know the details, but it is a lot quicker to
just tell the driver to take you to the airport.
4 chapter 1 Welcome Aboard

Even the statement “Go down this street ten blocks …” can be broken down
further with instructions on using the accelerator, the steering wheel, watching
out for other vehicles, pedestrians, etc.
Abstraction is a technique for establishing a simpler way for a person to inter-
act with a system, removing the details that are unnecessary for the person to
interact effectively with that system. Our ability to abstract is very much a pro-
ductivity enhancer. It allows us to deal with a situation at a higher level, focusing
on the essential aspects, while keeping the component ideas in the background.
It allows us to be more efficient in our use of time and brain activity. It allows us
to not get bogged down in the detail when everything about the detail is working
just fine.
There is an underlying assumption to this, however: when everything about
the detail is just fine. What if everything about the detail is not just fine? Then,
to be successful, our ability to abstract must be combined with our ability to
un-abstract. Some people use the word deconstruct—the ability to go from the
abstraction back to its component parts.
Two stories come to mind.
The first involves a trip through Arizona the first author made a long time
ago in the hottest part of the summer. At the time he was living in Palo Alto,
California, where the temperature tends to be mild almost always. He knew
enough to take the car to a mechanic before making the trip and tell him to check
the cooling system. That was the abstraction: cooling system. What he had not
mastered was that the capability of a cooling system for Palo Alto, California,
is not the same as the capability of a cooling system for the summer deserts of
Arizona. The result: two days in Deer Lodge, Arizona (population 3), waiting for
a head gasket to be shipped in.
The second story (perhaps apocryphal) is supposed to have happened during
the infancy of electric power generation. General Electric Co. was having trouble
with one of its huge electric power generators and did not know what to do. On
the front of the generator were lots of dials containing lots of information, and
lots of screws that could be rotated clockwise or counterclockwise as the operator
wished. Something on the other side of the wall of dials and screws was malfunc-
tioning and no one knew what to do. As the story goes, they called in one of the
early giants in the electric power industry. He looked at the dials and listened to
the noises for a minute, then took a small screwdriver from his pocket and rotated
one screw 35 degrees counterclockwise. The problem immediately went away. He
submitted a bill for $1000 (a lot of money in those days) without any elaboration.
The controller found the bill for two minutes’ work a little unsettling and asked
for further clarification. Back came the new bill:

Turning a screw 35 degrees counterclockwise: $ 0.75


Knowing which screw to turn and by how much: 999.25

In both stories the message is the same. It is more efficient to think of entities
as abstractions. One does not want to get bogged down in details unnecessarily.
And as long as nothing untoward happens, we are OK. If there had been no trip
to Arizona, the abstraction “cooling system” would have been sufficient. If the
1.3 Two Recurring Themes 5

electric power generator never malfunctioned, there would have been no need for
the power engineering guru’s deeper understanding.
As we will see, modern computers are composed of transistors. These tran-
sistors are combined to form logic “gates”—an abstraction that lets us think in
terms of 0s and 1s instead of the varying voltages on the transistors. A logic cir-
cuit is a further abstraction of a combination of gates. When one designs a logic
circuit out of gates, it is much more efficient to not have to think about the inter-
nals of each gate. To do so would slow down the process of designing the logic
circuit. One wants to think of the gate as a component. But if there is a problem
with getting the logic circuit to work, it is often helpful to look at the internal
structure of the gate and see if something about its functioning is causing the
problem.
When one designs a sophisticated computer application program, whether it
be a new spreadsheet program, word processing system, or computer game, one
wants to think of each of the components one is using as an abstraction. If one
spent time thinking about the details of each component when it was not neces-
sary, the distraction could easily prevent the total job from ever getting finished.
But when there is a problem putting the components together, it is often useful to
examine carefully the details of each component in order to uncover the problem.
The ability to abstract is the most important skill. In our view, one should
try to keep the level of abstraction as high as possible, consistent with getting
everything to work effectively. Our approach in this book is to continually raise
the level of abstraction. We describe logic gates in terms of transistors. Once we
understand the abstraction of gates, we no longer think in terms of transistors.
Then we build larger structures out of gates. Once we understand these larger
abstractions, we no longer think in terms of gates.

The Bottom Line Abstractions allow us to be much more efficient in dealing


with all kinds of situations. It is also true that one can be effective without under-
standing what is below the abstraction as long as everything behaves nicely. So,
one should not pooh-pooh the notion of abstraction. On the contrary, one should
celebrate it since it allows us to be more efficient.
In fact, if we never have to combine a component with anything else into a
larger system, and if nothing can go wrong with the component, then it is perfectly
fine to understand this component only at the level of its abstraction.
But if we have to combine multiple components into a larger system, we
should be careful not to allow their abstractions to be the deepest level of our
understanding. If we don’t know the components below the level of their abstrac-
tions, then we are at the mercy of them working together without our intervention.
If they don’t work together, and we are unable to go below the level of abstraction,
we are stuck. And that is the state we should take care not to find ourselves in.

1.3.2 Hardware vs. Software


Many computer scientists and engineers refer to themselves as hardware people
or software people. By hardware, they generally mean the physical computer and
6 chapter 1 Welcome Aboard

all the specifications associated with it. By software, they generally mean the pro-
grams, whether operating systems like Android, ChromeOS, Linux, or Windows,
or database systems like Access, MongoDB, Oracle, or DB-terrific, or applica-
tion programs like Facebook, Chrome, Excel, or Word. The implication is that
the person knows a whole lot about one of these two things and precious little
about the other. Usually, there is the further implication that it is OK to be an
expert at one of these (hardware OR software) and clueless about the other. It is
as if there were a big wall between the hardware (the computer and how it actu-
ally works) and the software (the programs that direct the computer to do their
bidding), and that one should be content to remain on one side of that wall or
the other.
The power of abstraction allows us to “usually” operate at a level where we
do not have to think about the underlying layers all the time. This is a good thing.
It enables us to be more productive. But if we are clueless about the underlying
layers, then we are not able to take advantage of the nuances of those underlying
layers when it is very important to be able to.
That is not to say that you must work at the lower level of abstraction and not
take advantage of the productivity enhancements that the abstractions provide.
On the contrary, you are encouraged to work at the highest level of abstraction
available to you. But in doing so, if you are able to, at the same time, keep in
mind the underlying levels, you will find yourself able to do a much better job.
As you approach your study and practice of computing, we urge you to take
the approach that hardware and software are names for components of two parts
of a computing system that work best when they are designed by people who take
into account the capabilities and limitations of both.
Microprocessor designers who understand the needs of the programs that
will execute on the microprocessor they are designing can design much more
effective microprocessors than those who don’t. For example, Intel, AMD, ARM,
and other major producers of microprocessors recognized a few years ago that a
large fraction of future programs would contain video clips as part of e-mail,
video games, and full-length movies. They recognized that it would be impor-
tant for such programs to execute efficiently. The result: most microprocessors
today contain special hardware capability to process those video clips. Intel
defined additional instructions, initially called their MMX instruction set, and
developed special hardware for it. Motorola, IBM, and Apple did essentially
the same thing, resulting in the AltiVec instruction set and special hardware to
support it.
A similar story can be told about software designers. The designer of a large
computer program who understands the capabilities and limitations of the hard-
ware that will carry out the tasks of that program can design the program so it
executes more efficiently than the designer who does not understand the nature of
the hardware. One important task that almost all large software systems need to
carry out is called sorting, where a number of items have to be arranged in some
order. The words in a dictionary are arranged in alphabetical order. Students in
a class are often graded based on a numerical order, according to their scores
on the final exam. There is a large number of fundamentally different programs
one can write to arrange a collection of items in order. Donald Knuth, one of the
1.4 A Computer System 7

top computer scientists in the world, devoted 391 pages to the task in The Art
of Computer Programming, vol. 3. Which sorting program works best is often
very dependent on how much the software designer is aware of the underlying
characteristics of the hardware.

The Bottom Line We believe that whether your inclinations are in the direction
of a computer hardware career or a computer software career, you will be much
more capable if you master both. This book is about getting you started on the
path to mastering both hardware and software. Although we sometimes ignore
making the point explicitly when we are in the trenches of working through a
concept, it really is the case that each sheds light on the other.
When you study data types, a software concept, in C (Chapter 12), you will
understand how the finite word length of the computer, a hardware concept,
affects our notion of data types.
When you study functions in C (Chapter 14), you will be able to tie the rules
of calling a function with the hardware implementation that makes those rules
necessary.
When you study recursion, a powerful algorithmic device (initially in
Chapter 8 and more extensively in Chapter 17), you will be able to tie it to the
hardware. If you take the time to do that, you will better understand when the
additional time to execute a procedure recursively is worth it.
When you study pointer variables in C (in Chapter 16), your knowledge of
computer memory will provide a deeper understanding of what pointers pro-
vide, and very importantly, when they should be used and when they should be
avoided.
When you study data structures in C (in Chapter 19), your knowledge of com-
puter memory will help you better understand what must be done to manipulate
the actual structures in memory efficiently.
We realize that most of the terms in the preceding five short paragraphs may
not be familiar to you yet. That is OK; you can reread this page at the end of the
semester. What is important to know right now is that there are important topics
in the software that are very deeply interwoven with topics in the hardware. Our
contention is that mastering either is easier if you pay attention to both.
Most importantly, most computing problems yield better solutions when the
problem solver has the capability of both at his or her disposal.

1.4 A Computer System


We have used the word computer more than two dozen times in the preceding
pages, and although we did not say so explicitly, we used it to mean a system
consisting of the software (i.e., computer programs) that directs and specifies the
processing of information and the hardware that performs the actual processing
of information in response to what the software asks the hardware to do. When
we say “performing the actual processing,” we mean doing the actual additions,
multiplications, and so forth in the hardware that are necessary to get the job
8 chapter 1 Welcome Aboard

done. A more precise term for this hardware is a central processing unit (CPU),
or simply a processor or microprocessor. This textbook is primarily about the
processor and the programs that are executed by the processor.

1.4.1 A (Very) Little History for a (Lot) Better Perspective


Before we get into the detail of how the processor and the software associated
with it work, we should take a moment and note the enormous and unparalleled
leaps of performance that the computing industry has made in the relatively short
time computers have been around. After all, it wasn’t until the 1940s that the
first computers showed their faces. One of the first computers was the ENIAC
(the Electronic Numerical Integrator and Calculator), a general purpose electronic
computer that could be reprogrammed for different tasks. It was designed and built
in 1943–1945 at the University of Pennsylvania by Presper Eckert and his colleagues.
It contained more than 17,000 vacuum tubes. It was approximately 8 feet high, more
than 100 feet wide, and about 3 feet deep (about 300 square feet of floor space). It
weighed 30 tons and required 140 kW to operate. Figure 1.1 shows three operators
programming the ENIAC by plugging and unplugging cables and switches.
About 40 years and many computer companies and computers later, in the
early 1980s, the Burroughs A series was born. One of the dozen or so 18-inch
boards that comprise that machine is shown in Figure 1.2. Each board contained
50 or more integrated circuit packages. Instead of 300 square feet, it took up
around 50 to 60 square feet; instead of 30 tons, it weighed about 1 ton, and instead
of 140 kW, it required approximately 25 kW to operate.

Figure 1.1 The ENIAC, designed and built at University of Pennsylvania, 1943–45.

c Historical/Getty Images
1.4 A Computer System 9

Figure 1.2 A processor board, vintage 1980s. Courtesy of Emilio Salguerio

Fast forward another 30 or so years and we find many of today’s computers on


desktops (Figure 1.3), in laptops (Figure 1.4), and most recently in smartphones
(Figure 1.5). Their relative weights and energy requirements have decreased
enormously, and the speed at which they process information has also increased
enormously. We estimate that the computing power in a smartphone today (i.e.,
how fast we can compute with a smartphone) is more than four million times the
computing power of the ENIAC!

Figure 1.3 Figure 1.4 A laptop. 


c Rob Figure 1.5 A smartphone. 
c Oleksiy
A desktop computer. Monk/Future/ Maksymenko/

c Joby Sessions/ REX/Shutterstock imageBROKER/REX/Shutterstock
Future/REX/
Shutterstock
10 chapter 1 Welcome Aboard

Figure 1.6 A microprocessor. 


c Peter Gudella/Shutterstock

The integrated circuit packages that comprise modern digital computers have
also seen phenomenal improvement. An example of one of today’s microproces-
sors is shown in Figure 1.6. The first microprocessor, the Intel 4004 in 1971,
contained 2300 transistors and operated at 106 KHz. By 1992, those numbers
had jumped to 3.1 million transistors at a frequency of 66 MHz on the Intel
Pentium microprocessor, an increase in both parameters of a factor of about 1000.
Today’s microprocessors contain upwards of five billion transistors and can oper-
ate at upwards of 4 GHz, another increase in both parameters of about a factor
of 1000.
This factor of one million since 1971 in both the number of transistors and
the frequency that the microprocessor operates at has had very important impli-
cations. The fact that each operation can be performed in one millionth of the
time it took in 1971 means the microprocessor can do one million things today
in the time it took to do one thing in 1971. The fact that there are more than a
million times as many transistors on a chip means we can do a lot more things at
the same time today than we could in 1971.
The result of all this is we have today computers that seem able to understand
the languages people speak – English, Spanish, Chinese, for example. We have
computers that seem able to recognize faces. Many see this as the magic of artifi-
cial intelligence. We will see as we get into the details of how a computer works
that much of what appears to be magic is really due to how blazingly fast very
simple mindless operations (many at the same time) can be carried out.

1.4.2 The Parts of a Computer System


When most people use the word computer, they usually mean more than just
the processor (i.e., CPU) that is in charge of doing what the software directs.
1.5 Two Very Important Ideas 11

They usually mean the collection of parts that in combination form their computer
system. Today that computer system is often a laptop (see Figure 1.4), augmented
with many additional devices.
A computer system generally includes, in addition to the processor, a key-
board for typing commands, a mouse or keypad or joystick for positioning on
menu entries, a monitor for displaying information that the computer system has
produced, memory for temporarily storing information, disks and USB memory
sticks of one sort or another for storing information for a very long time, even after
the computer has been turned off, connections to other devices such as a printer
for obtaining paper copies of that information, and the collection of programs
(the software) that the user wishes to execute.
All these items help computer users to do their jobs. Without a printer, for
example, the user would have to copy by hand what is displayed on the monitor.
Without a mouse, keypad, or joystick, the user would have to type each command,
rather than simply position the mouse, keypad, or joystick.
So, as we begin our journey, which focuses on the CPU that occupies a small
fraction of 1 square inch of silicon and the software that makes the CPU do our
bidding, we note that the computer systems we use contain a lot of additional
components.

1.5 Two Very Important Ideas


Before we leave this first chapter, there are two very important ideas that we
would like you to understand, ideas that are at the core of what computing is all
about.
Idea 1: All computers (the biggest and the smallest, the fastest and the
slowest, the most expensive and the cheapest) are capable of comput-
ing exactly the same things if they are given enough time and enough
memory. That is, anything a fast computer can do, a slow computer can
do also. The slow computer just does it more slowly. A more expensive
computer cannot figure out something that a cheaper computer is unable
to figure out as long as the cheaper computer can access enough mem-
ory. (You may have to go to the store to buy more memory whenever it
runs out of memory in order to keep increasing memory.) All computers
can do exactly the same things. Some computers can do things faster,
but none can do more than any other.
Idea 2: We describe our problems in English or some other language
spoken by people. Yet the problems are solved by electrons running
around inside the computer. It is necessary to transform our problem
from the language of humans to the voltages that influence the flow of
electrons. This transformation is really a sequence of systematic trans-
formations, developed and improved over the last 70 years, which
combine to give the computer the ability to carry out what appear to
12 chapter 1 Welcome Aboard

be some very complicated tasks. In reality, these tasks are simple and
straightforward.
The rest of this chapter is devoted to discussing these two ideas.

1.6 Computers as Universal


Computational Devices
It may seem strange that an introductory textbook begins by describing how
computers work. After all, mechanical engineering students begin by studying
physics, not how car engines work. Chemical engineering students begin by
studying chemistry, not oil refineries. Why should computing students begin by
studying computers?
The answer is that computers are different. To learn the fundamental prin-
ciples of computing, you must study computers or machines that can do what
computers can do. The reason for this has to do with the notion that computers
are universal computational devices. Let’s see what that means.
Before modern computers, there were many kinds of calculating machines.
Some were analog machines—machines that produced an answer by measuring
some physical quantity such as distance or voltage. For example, a slide rule is
an analog machine that multiplies numbers by sliding one logarithmically graded
ruler next to another. The user can read a logarithmic “distance” on the sec-
ond ruler. Some early analog adding machines worked by dropping weights on a
scale. The difficulty with analog machines is that it is very hard to increase their
accuracy.
This is why digital machines—machines that perform computations by
manipulating a fixed finite set of digits or letters—came to dominate comput-
ing. You are familiar with the distinction between analog and digital watches. An
analog watch has hour and minute hands, and perhaps a second hand. It gives
the time by the positions of its hands, which are really angular measures. Digital
watches give the time in digits. You can increase accuracy just by adding more
digits. For example, if it is important for you to measure time in hundredths of
a second, you can buy a watch that gives a reading like 10:35.16 rather than just
10:35. How would you get an analog watch that would give you an accurate read-
ing to one one-hundredth of a second? You could do it, but it would take a mighty
long second hand! When we talk about computers in this book, we will always
mean digital machines.
Before modern digital computers, the most common digital machines in the
West were adding machines. In other parts of the world another digital machine,
the abacus, was common. Digital adding machines were mechanical or elec-
tromechanical devices that could perform a specific kind of computation: adding
integers. There were also digital machines that could multiply integers. There
were digital machines that could put a stack of cards with punched names in
alphabetical order. The main limitation of all these machines is that they could
do only one specific kind of computation. If you owned only an adding machine
1.6 Computers as Universal Computational Devices 13

and wanted to multiply two integers, you had some pencil-and-paper work
to do.
This is why computers are different. You can tell a computer how to add num-
bers. You can tell it how to multiply. You can tell it how to alphabetize a list or
perform any computation you like. When you think of a new kind of computation,
you do not have to buy or design a new computer. You just give the old computer
a new set of instructions (a program) to carry out the new computation. This is
why we say the computer is a universal computational device. Computer scien-
tists believe that anything that can be computed, can be computed by a computer
provided it has enough time and enough memory. When we study computers, we
study the fundamentals of all computing. We learn what computation is and what
can be computed.
The idea of a universal computational device is due to Alan Turing. Turing
proposed in 1937 that all computations could be carried out by a particular kind of
machine, which is now called a Turing machine. He gave a mathematical descrip-
tion of this kind of machine, but did not actually build one. Digital computers
were not operating until several years later. Turing was more interested in solv-
ing a philosophical problem: defining computation. He began by looking at the
kinds of actions that people perform when they compute; these include making
marks on paper, writing symbols according to certain rules when other symbols
are present, and so on. He abstracted these actions and specified a mechanism that
could carry them out. He gave some examples of the kinds of things that these
machines could do. One Turing machine could add two integers; another could
multiply two integers.
Figure 1.7 shows what we call “black box” models of Turing machines that
add and multiply. In each case, the operation to be performed is described in
the box. The data elements on which to operate are shown as inputs to the box.
The result of the operation is shown as output from the box. A black box model
provides no information as to exactly how the operation is performed, and indeed,
there are many ways to add or multiply two numbers.

TADD TMUL
a, b a+b a, b a×b
(Turing machine (Turing machine
that adds) that multiplies)

Figure 1.7 Black box models of Turing machines.

Turing proposed that every computation can be performed by some Turing


machine. We call this Turing’s thesis. Although Turing’s thesis has never been
proved, there does exist a lot of evidence to suggest it is true. We know, for exam-
ple, that various enhancements one can make to Turing machines do not result in
machines that can compute more.
Perhaps the best argument to support Turing’s thesis was provided by Turing
himself in his original paper. He said that one way to try to construct a machine
more powerful than any particular Turing machine was to make a machine U
that could simulate all Turing machines. You would simply describe to U the
14 chapter 1 Welcome Aboard

particular Turing machine you wanted it to simulate, say a machine to add two
integers, give U the input data, and U would compute the appropriate output,
in this case the sum of the inputs. Turing then showed that there was, in fact,
a Turing machine that could do this, so even this attempt to find something that
could not be computed by Turing machines failed.
Figure 1.8 further illustrates the point. Suppose you wanted to compute
g ⋅ (e + f ). You would simply provide to U descriptions of the Turing machines
to add and to multiply, and the three inputs, e, f , and g. U would do the rest.

TADD, TMUL
U
g × (e + f )

e, f, g (Universal
Turing machine)

Figure 1.8 Black box model of a universal Turing machine.

In specifying U, Turing had provided us with a deep insight: He had given us


the first description of what computers do. In fact, both a computer (with as much
memory as it wants) and a universal Turing machine can compute exactly the
same things. In both cases, you give the machine a description of a computation
and the data it needs, and the machine computes the appropriate answer. Comput-
ers and universal Turing machines can compute anything that can be computed
because they are programmable.
This is the reason that a big or expensive computer cannot do more than a
small, cheap computer. More money may buy you a faster computer, a monitor
with higher resolution, or a nice sound system. But if you have a small, cheap
computer, you already have a universal computational device.

1.7 How Do We Get the Electrons to


Do the Work?
Figure 1.9 shows the process we must go through to get the electrons (which
actually do the work) to do our bidding. We call the steps of this process the
“Levels of Transformation.” As we will see, at each level we have choices. If we
ignore any of the levels, our ability to make the best use of our computing system
can be very adversely affected.

1.7.1 The Statement of the Problem


We describe the problems we wish to solve in a “natural language.” Natural lan-
guages are languages that people speak, like English, French, Japanese, Italian,
and so on. They have evolved over centuries in accordance with their usage.
They are fraught with a lot of things unacceptable for providing instructions to a
1.7 How Do We Get the Electrons to Do the Work? 15

Problems

Algorithms

Language

Machine (ISA) Architecture

Microarchitecture

Circuits

Devices
Figure 1.9 Levels of transformation.

computer. Most important of these unacceptable attributes is ambiguity. Natural


language is filled with ambiguity. To infer the meaning of a sentence, a listener is
often helped by the tone of voice of the speaker, or at the very least, the context
of the sentence.
An example of ambiguity in English is the sentence, “Time flies like an
arrow.” At least three interpretations are possible, depending on whether (1) one is
noticing how fast time passes, (2) one is at a track meet for insects, or (3) one is
writing a letter to the Dear Abby of Insectville. In the first case, a simile; one
is comparing the speed of time passing to the speed of an arrow that has been
released. In the second case, one is telling the timekeeper to do his/her job much
like an arrow would. In the third case, one is relating that a particular group of
flies (time flies, as opposed to fruit flies) are all in love with the same arrow.
Such ambiguity would be unacceptable in instructions provided to a com-
puter. The computer, electronic idiot that it is, can only do as it is told. To tell it to
do something where there are multiple interpretations would cause the computer
to not know which interpretation to follow.
16 chapter 1 Welcome Aboard

1.7.2 The Algorithm


The first step in the sequence of transformations is to transform the natural lan-
guage description of the problem to an algorithm, and in so doing, get rid of the
objectionable characteristics of the natural language. An algorithm is a step-by-
step procedure that is guaranteed to terminate, such that each step is precisely
stated and can be carried out by the computer. There are terms to describe each
of these properties.
We use the term definiteness to describe the notion that each step is precisely
stated. A recipe for excellent pancakes that instructs the preparer to “stir until
lumpy” lacks definiteness, since the notion of lumpiness is not precise.
We use the term effective computability to describe the notion that each step
can be carried out by a computer. A procedure that instructs the computer to “take
the largest prime number” lacks effective computability, since there is no largest
prime number.
We use the term finiteness to describe the notion that the procedure termi-
nates.
For every problem there are usually many different algorithms for solving
that problem. One algorithm may require the fewest steps. Another algorithm
may allow some steps to be performed concurrently. A computer that allows
more than one thing to be done at a time can often solve the problem in less
time, even though it is likely that the total number of steps to be performed has
increased.

1.7.3 The Program


The next step is to transform the algorithm into a computer program in one of the
programming languages that are available. Programming languages are “mechan-
ical languages.” That is, unlike natural languages, mechanical languages did not
evolve through human discourse. Rather, they were invented for use in specify-
ing a sequence of instructions to a computer. Therefore, mechanical languages do
not suffer from failings such as ambiguity that would make them unacceptable for
specifying a computer program.
There are more than 1000 programming languages. Some have been designed
for use with particular applications, such as Fortran for solving scientific calcula-
tions and COBOL for solving business data-processing problems. In the second
half of this book, we will use C and C++, languages that were designed for
manipulating low-level hardware structures.
Other languages are useful for still other purposes. Prolog is the language of
choice for many applications that require the design of an expert system. LISP
was for years the language of choice of a substantial number of people working
on problems dealing with artificial intelligence. Pascal is a language invented as
a vehicle for teaching beginning students how to program.
There are two kinds of programming languages, high-level languages and
low-level languages. High-level languages are at a distance (a high level) from
the underlying computer. At their best, they are independent of the computer on
which the programs will execute. We say the language is “machine independent.”
Another random document with
no related content on Scribd:
The Project Gutenberg eBook of Ei-jumalainen
komedia
This ebook is for the use of anyone anywhere in the United States
and most other parts of the world at no cost and with almost no
restrictions whatsoever. You may copy it, give it away or re-use it
under the terms of the Project Gutenberg License included with this
ebook or online at www.gutenberg.org. If you are not located in the
United States, you will have to check the laws of the country where
you are located before using this eBook.

Title: Ei-jumalainen komedia

Author: hrabia Zygmunt Krasiński

Translator: Jalo Lahja Kalima

Release date: April 2, 2024 [eBook #73321]

Language: Finnish

Original publication: Helsinki: Otava, 1909

Credits: Tuula Temonen

*** START OF THE PROJECT GUTENBERG EBOOK EI-


JUMALAINEN KOMEDIA ***
EI-JUMALAINEN KOMEDIA

Kirj.

Zygmunt Krasinski

Puolan kielestä suomentanut

Jalo Kalima

Helsingissä, Kustannusosakeyhtiö Otava, 1909.


KIRJALLISHISTORIALLINEN
JOHDANTO.

Jos kirjallishistoriallinen esipuhe on yleensä omiaan luomaan valoa


kirjallisuuden merkkiteoksiin, on se »Ei-jumalaisen komedian»
ymmärtämiselle erikoisen tarpeellinen. Sillä me olemme siinä
tekemisissä sangen omasävyisen kirjailijapersonallisuuden kanssa,
jonka filosofinen, aatteellisissa kuvissa askarteleva runoilija-henki ei
uhraa mitään helppotajuisuudelle. Mutta jos tutustuminen tähän
kirjailijaan vaatiikin hiukan enemmän vaivannäköä, on uuden
tuttavuuden tarjooma henkinen sisältö siksi kallisarvoinen, että sen
vaivannäön mielellään unohtaa.

Seuraavan pienen katsauksen tarkoituksena olisi antaa tästä


puolalaisesta runoilijasta sellaisia kirjallishistoriallisia tietoja ja
selityksiä, jotka valaisevat hänen kehitystään ja varsinkin ovat
tarpeellisia sen teoksen ymmärtämiseksi, joka tässä nyt ilmestyy
suomenkielisessä asussa.

»Ei-jumalaisen komedian» kirjoittajalla, Zygmunt Krasinskilla on


kirjallisuushistoriassa vakaantunut sijansa kolmantena Puolan
suurten runoilijain kolmimiehisessä ryhmässä. Hänellä ei ole
Mickiewiczin — Puolan ja kaikkien slaavilaisten maitten suurimman
runoilijan — syvää elämäntuntoa ja elävää maalauksellisuutta, eikä
myöskään toisen maamiehensä ja aikalaisensa Slowackin
helmeilevää runorikkautta, mutta hänellä on edellisiä kauemmas
tähtäävä katse ja suurpiirteisempään filosofiseen tarkasteluun
taipuva henki.

Syntyperältään oli Krasinski puhdasverinen aristokratti. Puolan


ylimystön vanhat katolisaateliset traditsionit olivat Krasinskin suvusta
saaneet monta kunniakasta puolustajaa. Kirjailijan isä Vincenty
Krasinski, uljas, lujaluontoinen ja kunnianhimoinen sotilas, oli liittynyt
puolalaisten jumaloimaan Napoleoniin ja voittanut laakereita hänen
armeijassaan keisarin adjutanttina ja puolalaisen osaston »Chevaux-
légers'in» päällikkönä.

Tämän napoleonilaisen kreivin ja ruhtinatar Maria Radziwillin


avioliitosta syntyi Parisissa helmikuun 12 p:nä 1812 tuleva
puolalainen kirjailija Zygmunt Krasinski. Napoleonin kukistuttua
muutti perhe Varsovaan, jossa kreivi Krasinski jatkoi sotilasuraansa
Aleksanteri I:n palveluksessa, vastaperustetun puolalaisen armeijan
kenraalina. Täällä sai tuleva runoilija mitä huolellisimman
kasvatuksen, jota ohjasi ensin eräs jalosukuinen ranskalainen
kotiopettajatar, sitten kyvyistään tunnetut miehiset kotiopettajat, m.m.
tunnettu puolalainen kirjailija Józef Korzeniowski.

Varakkaan ylimyskodin ainoana lapsena kasvaen, omaisten,


kotiopettajain ja ystäväin alituisen huomion ja huolenpidon
ympäröimänä, joutui tuleva kirjailija luonnottoman varhaisen
kehityksen alaiseksi. Paitsi kodin ansari-ilmaa vaikutti siihen ennen
kaikkea pojan herkkä luonne, jonka hän hennon
ruumiinrakennuksensa ohella oli perinyt sairaloisen herkältä,
melankoliaan taipuvalta äidiltään. Kerrotaan pojan jo kuusivuotiaana
kirjoittaneen kotiopettajattarelleen ranskankielisen kertomuksen. Se
on kuitenkin perhetarina, jonka todenperäisyyttä on vaikea taata.
Mutta viiden-, kuudentoista ikäisenä hän jo kirjoitteli pitkiä
kertomuksia, joista osa on painettukin.

Tätä kirjallista harrastusta ei riitä selittämään pelkkä luontainen


kutsumus eikä kasvatuksen antamat vaikutelmat, vaan
huomattavana tekijänä siinä oli ajan yleinen runollinen innostus,
romantikan keväinen kuohunta, jonka pirskahtelut tuntuivat jo
Varsovan lahjakkaimman nuorison keskuudessa ja josta nuori
Zygmunt ei voinut jäädä tietämättömäksi. Lyseossa ja sittemmin
yliopistossa tuli Krasinski välittömään kosketukseen sen nuorison
kanssa.

Ajan suuret romantikot ne ensin leimahuttelivat hänen


mielikuvitustaan. Byronin demoninen intohimo, Walter Scottin
värikkäät menneisyyden kuvat ritari-elämän kangastuksineen, Victor
Hugon veristä julmuutta huokuvat nuoruudenteokset olivat nuoren
Krasinskin kuumeisen hengen himoruokana. Kokonaan niiden
vaikutuksen alaisena kirjoitti vasta nuoruusikään astunut runoilija
joukon teoksia, joista useimmat ovat laajoja pseudohistoriallisia
romaneja hurjan intohimoisine sankareineen ja pöyristyttävine
situatsioneineen.

Krasinski ei ollut vielä kasvanut siksi, mikä hänestä tuleva oli, ja


siksi saattoi hän tulla ainoastaan vakavain elämänkokemusten ja
niistä johtuvien sielullisten kamppailujen kautta… Ensimäiset
vakavat kokemukset johtuivat runoilijan suhteessa isäänsä.

Tämä entinen napoleonilainen upseeri oli siihen määrin


järkähtämätön uskollisuudessaan uutta herraansa Venäjän keisaria
kohtaan, että hänen valtiollista malttiaan ja varovaisuuttaan alettiin
vähitellen pitää venäjänmielisyytenä. Täydelliseen epäsuosioon
omien kansalaistensa kesken joutui hän senjälkeen kun hän oli yksin
n.s. »valtiopäivä-oikeudessa» äänestänyt kuolemanrangaistusta
erään salaisen isänmaallisen kumousseuran sotilas-jäsenille.

Zygmunt oli silloin Varsovan yliopistossa, sen juridisessa


tiedekunnassa. Suhteessaan isään, joka äidin varhain kuoltua oli
hänen ainoa läheinen omaisensa, oli Zygmunt aina ollut kuuliainen ja
kunnioittava lapsi ja sellaisena pysyi hän koko elämänsä läpi. Juuri
tästä kuuliaisuudesta johtui hänen ensimäinen kova personallinen
kokemuksensa. Äsken mainitun »valtiopäivä-oikeuden» esimies oli
kuollut, ja koko akademinen nuorisoparvi otti mieltään-osoittavasti
osaa hautajaisiin. Zygmunt yksin tuli isänsä käskystä eräälle
luennolle. Seuraavana päivänä hän sai tovereiltaan suurinta
ylenkatsetta osakseen. Häneltä revittiin kaikki akademiset merkit ja
hänet saatettiin ulos luentosalista. Nuori Zygmunt vaati häväistyksen
johtajaa kaksintaisteluun, mutta kenraali katsoi parhaaksi kiireimmän
kautta lähettää poikansa rajan yli ulkomaille.

Arvelemme tämän yliopistomuiston olleen ensimäisenä virikkeenä


sen tunne- ja ajatuselämän syttymiseen, joka muutama vuosi
myöhemmin johtaa kirjailijan »Ei-jumalaisen komedian» luomiseen.
Eräässä myöhemmässä teoksessaan (Niedokończony poemat),
muistellessaan tätä tapausta, kertoo runoilija toverien silloin
huutaneen hänelle »panicz, panicz!» (herraspoika, herraspoika!) ja
lisää: »ikäänkuin se olisi häpeä, että voin osoittaa, missä niin moni
esi-isistäni on antanut henkensä isänmaan edestä ja missä kirkossa
kukin heistä nyt lepää». Päättäen tästä tunsi nuori ylimyssukuinen
kirjailija silloin ensi kerran aristokratin aseman traagillisuuden
kasvavan demokratian keskellä.
Jätettyään kotimaansa 1829 asettui Krasinski Geneveen. Täällä
hän ystävystyi erään hienosti sivistyneen englantilaisen Henry
Reeve'n kanssa ja sai häneltä hyviä vaikutelmia. Vielä syvemmän
jäljen jätti tutustuminen isänmaastaan karkoitettuun Mickiewicziin
kesällä 1830. Keskusteluista suuren runoilijan kanssa hänelle
selveni, että — kuten hän kirjoittaa — »kaikki melu on tyhmyyttä, niin
kirjoituksessa, teossa kuin puheessakin; että totuus ja totuus yksin
voi olla kaunis ja kiehtova meidän aikanamme; että kaikki koristeet ja
tyylikuvat ovat tyhjää, — kun ajatus puuttuu; että jos mieli olla jotain
nykyään, on opiskeltava, opiskeltava ja etsittävä totuutta kaikkialta,
antamatta hetken virvatulien vietellä itseään, sillä ne sammuvat kuin
kiiltomadot toukokuun nurmella…»

Mutta enin kasvattivat kirjailijaa seuraavien vuosien sisäiset


kamppailut. V:na 1830 oli Krasinski saapunut Roomaan ja ajatukset
sen entisen mahtavuuden katoamisesta liikkuivat voimakkaina
hänen sielussaan, kun saapui viesti Puolan kapinasta. Hänen
ensimäinen ajatuksensa oli silloin kiiruhtaa taistelutantereelle
isänmaataan puolustamaan. Hän halusi sinne sitä kiihkeämmin kun
hän tunsi itsensä väärin tuomituksi. Mutta isän kielto pidätti häntä.
Hänen polttava epätoivonsa kuvastuu hänen muutamassa
senaikuisessa kertomuksessaan, jossa ensi kerran tuntuu selvä
personallinen sävy, ja useissa ranskankielisissä kirjeissä
geneveläiselle ystävälleen Reeve'lle.

Se synnynnäinen taipumus mietiskelyyn ja skeptillisyyteen, joka


runoilijassa oli haaveellisuuden ohella, auttoi häntä vähitellen
tyyntymään ja opetti viileämmin asioita arvostelemaan. Sitä paitsi oli
isä kirjeissään kiinnittänyt pojan huomiota tämän kapinataistelun
toiseen puoleen, joka suuntasi runoilijan mietteet laajemmille aloille,
yleisinhimillisten kysymysten piiriin. »Kansallisuudet ovat kadonneet
— oli kenraali kirjoittanut — kaksi lippua hallitsee maailmaa: järjestys
ja anarkia, ja kaikki tarkoittaa sitä, että ne, jotka omistavat, eivät
omistaisi ja että ne, jotka eivät omista, tulisivat omistamaan».

Nuori herkkä runoilija, jonka mielenliikutuksista järkkynyt terveys


pakoitti tuontuostakin kamarin yksinäisyyteen, ryhtyi ajatuksissaan
tarkastamaan Europan valtiollisen ja yhteiskunnallisen elämän
ilmiöitä.

Wienin kongressista asti olivat kumoukselliset virtaukset alkaneet


yhä enemmän vavahutella Europan monarkistista valtiojärjestystä.
Dekabristien kapinan jälkeen Pietarissa (1825) ilmeni kumouksellista
kiehuntaa ympäri Europpaa, kunnes se leimahti ilmiliekkiin melkein
yhtaikaa Ranskassa, Puolassa ja Belgiassa. Nämä liikkeet olivat
kuitenkin enemmän valtiollista laatua. Mutta syvemmällä koko
olevaisen yhteiskuntajärjestyksen pohjalla tuntui kytevän voimakas
yhteiskuntataloudellinen kumousliike. Sillä oli omat apostolinsa —
ennen muita ranskalainen Saint-Simon ja hänen oppilaansa Bazard
ja Enfantin — jotka saarnasivat koko yhteiskuntajärjestyksen
muuttamista, naisten ja työtätekeväin luokkien vapauttamista,
omaisuuden yhteistyttämistä, sääty-etuoikeuksien ja kirkon —
etenkin katolisen — suistamista ja uuden uskon perustamista.

Siihen taisteluun kiintyi ylimyssukuisen runoilijan katse. Erikoisen


merkitseväksi tuli hänelle tapaus, joka sattui vuosi jälkeen Puolan
kapinan Lyonissa Ranskanmaalla ja jonka viestit saapuivat hänelle
Geneveen. Se oli 40,000:n nälkääntyneen silkkityöntekijän
marraskuussa 1831 puhjennut kapina, joka vei julmiin
katutaisteluihin ja verenvuodatukseen… Tämän kapinan jälkeen
kirjoittaa Krasinski eräässä kirjeessään: »Silminnähtävää on, että
pian lähenee Europan nykyisen yhteiskuntajärjestyksen häviö, että
tasapaino on kaikkialta rikkoutunut, sopu turmeltu, perusteet
horjutetut, ja pyörteiden ja kiistan verhossa pyrkii jotain uutta
tuntematonta etukynteen ja valtaamaan maailmaa. Olemme
samassa asemassa kuin oli muinoin barbarien hyökkäyksistä
kuoleva Rooman valtakunta. Ainoana panssarinamme on usko
Kristukseen.»

Tämä kirjeen-ote viittaa selvästi ei ainoastaan »Ei-jumalaiseen


komediaan», vaan myös »Iridioniin», Krasinskin toiseen
pääteokseen.

Genevestä tuli kirjailija isänsä käskystä surulliseen,


kapinanjälkeiseen Varsovaan ja sieltä Pietariin, jonne kenraali oli
kapinan jälkeen muuttanut. Isä tahtoi tehdä pojastaan valtiomiehen,
mutta siitä kirjailijalle itselleen vastenmielisestä toiminnasta pelasti
hänet sisäisissä taisteluissa kehittynyt hermo- ja silmätauti. Kirjailijan
koko virkaura rajoittui audienssiin keisarin luona. Koko muun
Pietarissa-olonsa ajan hän pysytteli huoneessaan lukien, kirjoitellen
ja ennen kaikkea mietiskellen. Näissä mietteissä selkeni hänen
runohenkensä täyteen tietoisuuteen. Täällä hän laski perustan
molemmille merkkiteoksilleen »Ei-jumalaiselle komedialle» ja
»Iridionille». Ja kun hän viimein saatuaan passin pääsi lähtemään
sumujen kaupungista takaisin ulkomaille terveyttään hoitamaan,
kirjoitti hän ensimäisessä suuressa pysähdyspaikassaan, Wienissä,
alun ensimäiseen täyskypsään, nerokkaaseen luomaansa, »Ei-
jumalaiseen komediaan», ja lopetti sen Venetsiassa samana
vuonna, 1833. Silloin hän oli kahdenkymmenen yhden vuoden
vanha. Painosta ilmestyi teos vasta pari vuotta myöhemmin
(Parisissa 1835) — ilman tekijän nimeä, kuten kaikki Krasinskin
teokset.
Mitä nuori runoilija oli yksinäisissä mietteissään ajatellut noiden
»kahden lipun» välisestä sodasta, »järjestyksen» ja vanhoillisen
ylimysvallan taistelusta »anarkiaa» ja demokratiaa vastaan, sen on
hän tässä teoksessa suppeiden, voimakkaiden ja kirkassointuisten
replikkien avulla loihtinut draamallisiksi kuviksi. Vakuutettuna siitä,
että runous »koskee koko ihmiskuntaa, eikä ainoastaan yhtä maata
ja yhtä ajan ja paikan tilkkua, että se valtaa siipiensä alle ikuisuuden
ja äärettömyyden», hän käsitteli kysymystä sen puhtaassa
yleisinhimillisyydessä, yleistäen ja symbolisoiden sekä aatteita että
niiden kannattajia. Hän veti äärimäiset johtopäätökset nykyisestä
asiaintilasta, hän tutkisteli teitten lopullista suuntaa ja määrää,
terästäen etsivän katseensa kauas tulevaisuuteen.

Teoksen piti tekijän oman tunnustuksen mukaan tulla


»puolustukseksi sille, mitä niin monet ryysyläiset koettavat repiä
alas: uskonnolle ja menneisyyden maineelle». Mutta runollinen
inspiratsioni ja kirkas totuudentunto ei sallinut hänen tulla
kummankaan puolen asianajajaksi, vaan antoi hänelle filosofin
laajasydämisen tasapuolisuuden koko yhteiskunnallisvaltiollisten
ilmiöitten kokonaisuuteen nähden. Se auttoi häntä katsomaan
rohkeasti totuutta silmiin, sellaisena kuin se aikojen takaa hänelle
kajasti. Ja sellaisena hän sen kuvasi ja se kuva tuli »syvä kuin meri
ja surullinen kuin kuolema», kuten Krasinskin paras elämänkertoja
on sanonut.

Vaikkakin tekijä tunsi sympatiojensa kuuluvan aristokratialle, johon


hän itse syntymän ja kasvatuksen sitein oli sidottu, ei se estänyt
häntä näkemästä siinä auttamattomia perikadon oireita. Esi-isiensä
rikoksiin on se ylimysluokka lisännyt »epäröinnän ja pelon» eikä sen
näennäinen alttarin ja isänmaan sekä esi-isien kunnian
puolustaminen voi säästää sitä kuolemanrangaistukselta ja sen
jälkeen unhoitukselta.

Näennäisesti on muita ylempänä kreivi Henrik, »mies», kuten


häntä draamassa kutsutaan — »Mies» oli alkuaan ajateltu koko
teoksen nimeksi —, aristokratian peloton ja taipumaton johtaja, joka
halveksii niitä, joihin on liittynyt. Mutta hänen luja omistautumisensa
aristokratian asian palvelukseen ei ole sisäisen vakaumuksen, vaan
kuvittelun ja järkeilyn tulos. Hän on auttamaton »romantikko»,
runoilija, jolle teatralisten asentojen ja deklamatoristen lauseiden
tavoittelu on tullut luonteeksi.

Vahingoksi teoksen yhtenäisyydelle on tekijä omistanut ensimäiset


kaksi näytöstä tämän »miehen» luonnekuvaukselle. Oikeastaan
voikin sanoa »Ei-jumalaisessa komediassa» yhdistyvän kaksi
draamaa: kreivi Henrikin oman personallisen ja yhteiskunnallis-
valtiollisen, joskin painopiste on jälkimäisessä. Tekijän ankara itse-
erittely on saanut hänen antamaan Henrikin luonnekuvaukselle niin
laajan sijan. Hän kuvaa siinä haaveen ja fantasian orjaksi joutuneen
»kaunosielun» — käyttääkseni nykyaikaista sanaa —, jolle todellinen
elämä velvollisuuksineen on proosaa ja joka rakastaa vain omia
mielikuviaan. Ajaessaan takaa kauneuden ja maineen fantomeja,
joilla helvetti häntä houkuttelee, hän tallaa maahan todellisuudessa
elävän vaimonsa koruttoman, uskollisen sielun, joka hämärtyy
surusta, ettei voi seurata rakastettuaan »runouden» maailmaan.
Krasinski tuomitsee sellaisen taiteen, joka on irtautunut elämästä ja
teoista. Teoksen ensi osan ihanien alkusanojen lopussa hän asettaa
sellaisen taiteen runoilijalle vastakohdaksi toisenlaisen, jossa runous
asuu itsetiedottomana, koko elämää ja toimintaa hedelmöittävänä
voimana, — sellaisen, jollaiseksi hän tunsi Mickiewicz'in.
Kreivi Henrikin vaimosta tulee mielipuolisuudessa runoilija. Eikä
siinä kyllin. Henrikin poika Orcio, surullinen, ennenaikaisesti
kehittynyt, pelkästä hengestä elävä lapsi, ainoa olento maan päällä,
jota Henrik todellisuudessa kykeni rakastamaan, tulee ikäänkuin
kohtalon ivasta myös runoilijaksi, ja siinä on hänen
onnettomuutensa. Lapsen hento organismi on tuomittu sortumaan
runollisten ajatusten ja vaikutelmain painon alle. Orcion syvästi
taiteelliseen kuvaan on tekijä ottanut piirteitä itsestään niiltä ajoilta,
jolloin hän vastoin muitten lasten tapoja ei »ratsastellut
keppihevosilla, ei huvitellut nukeilla», vaan luki, kirjoitteli ja haaveili…
Orcio tulee sokeaksi — se on symboli aristokratian ruumiillisesta
degeneroinnasta —, ja Henrik tuntee elämänsä tyhjyyden ja ikävän.
Silloin puhuu hänelle suojelusenkelin hahmossa paremman
tietoisuuden ääni kutsuen häntä rakkauden työhön. Mutta taaskin
voittaa korskea deklamoiva runous, joka kotkana ilmestyy
kehoittamaan Henrikiä maineen ja kunnian tekoihin.

Kolmannen osan alusta alkaa varsinainen yhteiskunta-draama.


Sen ydinkohtana lienee pidettävä kreivi Henrikin l. »miehen» salaista
vaellusta demokratian leirin läpi. Siitä on teos saanut nimensä. Kuten
Dantella »Jumalaisessa komediassa» on »miehelläkin» opastajansa,
ei kuitenkaan mikään enkelimäinen Beatrice, vaan revolutsionin
sameassa vedessä kalastava viekas egoisti, »kastettu juutalainen»».
(Juutalaisia oli paljon saint-simonistisissa järjestöissä.) Näyt, jotka
»miehelle» avautuvat tällä öisellä retkellä, ovat kaikkea muuta kuin
jumalaisia. (Ne nojautuvat kertomuksiin jakobinien klubeista
Ranskan suuren vallankumouksen aikana 1793.)

Hälisevä lauma pyrkii vain aineelliseen nautintoon vanhan elämän-


järjestyksen raunioilla. Se on juonut herrainsa viinit ja teurastanut
kyntöhärkänsä yhteisiin pitoihin. Se ei näytä aavistavan, että sen,
jollei se tahdo nälkään kuolla, on pian ryhtyminen työhön taas, ja
siltä on, ruumiin- ja hengenvoimien erilaisuuden takia, nouseva
ennen pitkää uusi ylimystö, jonka ituja jo tuntuu joukon keskuudessa.

Demokratian etunenässä on Pankratius. Hän on lauman valtias,


kunnianhimoinen, kylmä, illusioniton järjen mies — »järjen, ei
sydämen, pois sydän ennakkoluuloineen». Suurten joukkojensa
kautta, jotka tottelevat häntä kuin Jumalaa, on hän Henrikiä
voimakkaampi, mutta luovaa voimaa ei hänessäkään ole. Hän ei
enää usko itseensä eikä asiaan, jota ajaa, ja hän halveksii
johtamaansa laumaa ja on sitä tuskin koskaan rakastanut.
Nousukkaan kunnianhimossaan tahtoisi hän saada valtansa alle
kreivi Henrikin, jonka hengen ylimyksellinen voima on hänet
imponoinut. Mutta kun moralinen triumfi osoittautuu mahdottomaksi,
on aseiden ratkaistava.

»Minä tiedän — kirjoittaa Krasinski eräässä kirjeessään, jota voi


pitää tämän teoksen paraimpana kommentariona — minä tiedän,
että meidän sivistyksemme lähenee kuolemaansa, tiedän, että
lähenevät ajat, jolloin uudet rikokset tulevat rankaisemaan vanhoja ja
saamaan tuomionsa Jumalan edessä. Mutta minä tiedän, etteivät ne
mitään luo, eivät mitään rakenna, menevät kuin Attilan ratsu ja autius
jää heidän jälkeensä! Vasta kun se, jota et sinä eikä kukaan tiedä
eikä käsitä, tulee, kehkeytyy kaaoksesta, on myös uusi Jumalan
tahdon mukainen maailma rakentuva ihmissukukunnan
edellämääräyksestä, mutta silloin ovat minun ja sinun luusi tomuna
ja tuhkana.»

Pankratiuksen joukot ovat voittaneet. Aristokratian viimeinen linna


on heidän hallussaan. Kreivi Henrik on syöksynyt linnanvallilta
kuiluun. Mutta Pankratius ei voi iloita katsellessaan kättensä töitä.
— »Katso noita aavikoita, noita suunnattomia aloja, jotka ovat
minun ja ajatukseni välillä. Nuo erämaat on kansoitettava, nuo kalliot
lohkaistava, nuo järvet yhdistettävä, jokaiselle annettava maa-
alansa, jotta syntyisi kaksi kertaa niin paljon elämää näille aavikoille,
kuin niillä nyt on kuolemaa. Muuten hävityksen työ ei ole sovitettu.»

Ja Pankratius tuntee voimattomuutensa siihen positiviseen työhön,


sillä hän on pyhittänyt elämänsä vihalle, eikä viha mitään rakenna.

Sen voiman, joka voi maailman uudistaa, on Krasinski


symbolisoinut siinä näyssä, jonka epäilyksen valtaama Pankratius
näkee: kuin Kristuksen tulemisen hetkenä häämöittää hänelle
autioituneen maailman yllä ristiinnaulitun kuva, jonka silmäin loistoa
hän ei kestä. Hän kuolee huutaen ne sanat, jotka tarinan mukaan
huusi kuollessaan kristinuskon rehellinen vihamies Julianus
Apostata: »Voitit, galilealainen!» Ja se huuto merkitsee sitä, ettei
veljesmurhat ja taistelut aineellisista eduista, vaan rakkaus yksin voi
saattaa ihmiskuntaa todelliseen onneen ja vapauteen. Tosin tämä
loppu tulee »Ei-jumalaisessa komediassa» hiukan odottamatta,
ilman taiteellista valmistelua ja psykologista perustelua. Mutta se on
sittenkin paras mahdollinen ja Krasinskille erikoisen
luonteenomainen.

»Ei-jumalaisen komedian» suuruus ja traagillinen syvyys on juuri


siinä, ettei kummallakaan taistelevista ole pelastavaa periaatetta
puolellaan. Runoilija ikäänkuin seisoo hajoavan maailman yllä ja
tuomitsee sitä puolueettomasti ja intohimottomasti, mutta ei
rakkaudettomasti.

En käy tässä syvemmin analysoimaan tämän teoksen taiteellista


vaikutusta, vaan jätän sen lukijan oman vaiston varaan. Sanon vain,
että teoksen vaikutusvoima ei ole vähääkään vähentynyt siitä, mikä
se oli teoksen kirjoittamishetkenä, 75 vuotta sitten.

*****

Krasinskin myöhemmästä elämästä ja tuotannosta mainitsen


tässä vain päätapaukset.

Talvella 1833—1834 hän oleskeli taas Roomassa ja seuraavana


vuonna hän kirjoitti toisen merkkiteoksensa, niinikään
näytelmämuotoisen proosarunoelman, »Iridionin», jonka
tapahtumapaikkana on Rooma. Siinä hän käsittelee kysymystä
kansallisvihasta. Iridion, näytelmän sankari, omistaa sille elämänsä
ja — hukkaa sen. Kreikkalaisen ja germanittaren poikana tahtoo hän
hävittää Rooman, kostaa isänmaansa häviön, mutta joutuu
keinoinaan käyttämänsä vihan ja pahuuden uhriksi. Mutta
näytelmään liitetyssä epilogissa antaa sovitusta kaipaava runoilija
taaskin ristin — rakkauden ja pyhityksen symbolin — voittaa.

Enkeli ja pahahenki taistelevat Iridionista. — Kuolematon


vihamieheni, hän on minun, hän on elänyt kostossa, hän on vihannut
Roomaa, — sanoo pahahenki.

— Hän on minun, — sanoo enkeli — sillä hän on rakastanut


Kreikkaansa.

Ja enkeli lähettää hänet Puolaan, »hautojen ja ristien maahan»,


kieltäymyksessä, marttyriudessa ja rakkauden töissä hakemaan
sovitusta erhetyksilleen.

1830-luvun lopulla Krasinski kiintyi Hegelin filosofiaan. Hänen


tuotantonsa kävi sen jälkeen yhä symbolistisemmaksi. »Kolmessa
ajatuksessa» tuntuu jo suuri slaavilaisuuden ihannoima ja
»Aamunsarastuksessa», joka ilmestyi v:na 1843, on se kehittynyt
oman kansallisuuden sairaalloiseksi jumaloimiseksi,
»messianismiksi». Puola on hänen mielestään marttyri kansojen
joukossa, ja sen marttyrius on kirkastava kansoille uuden ajan
suuren aatteen: kansainvälisten suhteitten kristillistymisen, politikan
sulautumisen uskontoon.

Krasinskin viimeinen huomattavampi teos on »Kolme psalmia»,


jonka juhlallisen vakavissa säkeissä väräjää tosin vanhoillinen mutta
syvä ja harras isänmaallinen mieli. Sen jälkeen esti heikkenevä
terveys ja kasvava sokeus Krasinskia enää kirjoittamasta. Hän kuoli
v:na 1859 Parisissa, missä oli syntynytkin.

Krasinskin ylevä näkökanta, voimakas ja värikäs tyyli sekä


kantava aatteellisuus takaavat hänelle vakavan aseman ei
ainoastaan Puolan vaan koko Europan kirjallisuudessa. Hänen
sopusoinnun ikävänsä ja rakkauden tien toistuva osoittamisensa
puhuu vähentymättömällä voimalla nykyaikaisellekin lukijalle.

Eino Kalima.

I
»Isiensä vikojen suureen joukkoon he lisäsivät sen, mistä
heidän esi-lsänsä eivät tienneet — epäröinnän ja pelon — ja
tapahtui, että he kahmivat maan pinnan päältä ja suuri
äänettömyys vain jäi heistä.»

Nimetön.

»To be or not to be, that is the question.»

Hamlet.

Pääsi ympärillä tähdet — jalkaisi alla meren aallot — meren


aalloilla ajaa sateenkaari hajoittaen sumut edestäsi — mitä näet, on
sinun rannat, kaupungit ja kansat ovat sinun — taivas on sinun
niinkuin ei kunniallasi olisi mitään vertaa.

Sinä soitat vieraille korville käsittämätöntä ihanuutta. Sinä punot


yhteen sydämiä ja irroitat kuin seppelettä, sormiesi leikiksi —
puserrat kyyneleitä — kuivaat ne hymylläsi, ja uudestaan ajat huulilta
hymyn hetkeksi — muutamiksi hetkiksi — väliin ainiaaksi. — Vaan
mitä tunnet itse? — Mitä teet itse? — Mitä ajattelet? — Sinun
kauttasi virtaa kauneuden vuo, vaan sinä et ole kauneus. — Voi
sinua — voi. — Lapsi, joka itkee imettäjänsä sylissä — kedon kukka,
joka ei tiedä tuoksunsa suloudesta, on arvokkaampi Herran edessä
kuin sinä.

*****

Mistä olet noussut sinä katoava varjo, joka kerrot valosta vaikka et
tunne valoa, et ole nähnyt etkä näe! Kuka on vihassaan tai
ivanhalussaan sinut luonut? — Kuka on antanut sinulle tuon kurjan
ja niin pettävän elämän, että osaat näytellä enkeliä juuri ennen kuin

You might also like