Showing posts with label assembler. Show all posts
Showing posts with label assembler. Show all posts

Monday, January 13, 2020

33209: School -- Parameter Stack

 Chapter 3.5: School -- BASIC vs. Pascal vs. Assembler

Chapter 3.6: School -- Reference Locality in Software

"I think we should talk a little more about variables and variable names. Remember this?" Professor Crane put the second Pascal version of the shoesz program up on the overhead projector.

program shoesz;

{ Print shoe size table with halves, by Thomas Bright and Rusty Crane }

procedure wrhalf( size: Real );
var
  ipart, numer: Integer;
begin
  ipart := trunc(size);
  numer := trunc((size-ipart+0.25)*2);
  if numer > 1 then
    begin
      numer := 0;
      ipart := ipart+1;
    end;
  write (ipart);
  if numer > 0 then 
    write (' 1/2')
end;

var conv: Char;
  st_sz, end_sz, sz, conv_sz: Real;
  dbl_sz: Integer;

const cm_in = 2.54;

begin
  conv := ' ';
  while (conv<>'E') AND (conv<>'M') do
  begin
    writeln ('Shoe Sizes');
    writeln ('Type E for English to Metric.');
    writeln ('Type M for Metric to English: ');
    readln (conv)
  end;

  writeln ('Start: ');
  readln (st_sz);
  writeln ('End: ');
  readln (end_sz);

  if conv = 'E' then
    writeln ('English => Metric')
  else
    writeln ('Metric => English');

  { Step by halves. }
  for dbl_sz := round(st_sz)*2 to round(end_sz)*2 do 
  begin
    sz := dbl_sz/2.0;
    if conv = 'E' then
      conv_sz := sz*cm_in
    else
      conv_sz := sz/cm_in;
    wrhalf(sz);
    write (chr(9), '=> ');
    wrhalf(conv_sz);
    writeln (chr(9), '(', sz , '=> ', conv_sz, ')')
  end
end.

"That was just what, two days ago?"

"Two classes ago. I think I have my copy here."

Several us dug out our notes from that day.

Professor Crane continued, "What do you think would happen if the size variable, sz, in the main procedure were to be renamed 'size', with the exact same spelling as the parameter size in the write-half routine?"

"Problems?" asked Lisa.

Mike's forehead furrowed in thought as he studied his copy of the source. "Well, you're calling the write-half routine from different places, with different variables. That means the names of the parameters you give it must not be going to conflict with the parameter name in the function."

I studied my own copy. "I think Mike's right. A size variable declared inside of write-half would probably conflict with the size parameter, but Pascal keeps the variable itself on the stack, and it must keep the name of variables local to the half write procedure separate in the dictionary somehow."

Professor Crane rolled his eyes and shook his head, then nodded. "They call that dictionary the symbol table."

Mike turned to give me a sharp look. "Stack?"

George groaned. "What's a stack?"

Pat reached over and poked George in the ribs. "Weren't either of you listening to me the other day?"

Everyone else turned toward Professor Crane. Becky asked, "What are they talking about?"

Professor Crane chuckled. "Something we call locality of reference. In Pascal and certain other languages, variables, constants, and other identifiers are only visible within the block they are declared in, and within blocks declared within the same block."

Pat and I exchanged glances and nods of understanding. Mike, George, and Lisa nodded, hesitantly. The rest of the class just gave him blank looks or shook their heads.

Professor Crane traded the slide for another:

program factfib;

function factorial( number: Integer ): Integer;
  begin
    if number > 0 then
      factorial := number*factorial(number-1)
    else
      factorial := 1;
  end;

function fibonacci( number: Integer ): Integer;
  begin
    if number > 1 then
      fibonacci := fibonacci(number-1)+fibonacci(number-2)
    else 
      fibonacci := number; 
  end;

var number: Integer;

begin
  for number := 0 to 7 do
  writeln( number, ': factorial:', factorial(number),
' fibonacci:', fibonacci(number) ); end.

"What do you think will happen? Will it be able to keep track of all those numbers?"

There were nods and shakes of the head and blank looks.

Andrea said, "I sure can't keep track of them all." 

She and Becky exchanged looks full of doubt.

"What do you think, Pat?" Professor Crane grinned.

Pat nodded. "Sure."

"How about you, Joe?"

"Oh, yeah. No problem. I'm not sure how the symbols are kept local to each scope in the symbol table, but the values are safe on the stack." I started doodling in 68000 assembler again.

"George?"

George scratched his chin. "Wouldn't factorial calling itself overwrite number?"

"Mike?"

"Joe and Pat keep saying something about stacks. Is that something magic where you can stack up the numbers and the compiler somehow keeps track of them all?"

"Very good." Professor Crane swapped slides again. 

"Does that look like a stack of plates to you? How's my artwork?"

There were a few complaints, but mostly hesitant nods. I put my pencil down to focus.

"If you put a plate on the stack, where do you put it? Usually, I mean."

Dirk volunteered, "In the center, especially if it's my mom asking me to."

"I don't know you." Lisa turned her head away and sniffed exaggeratedly.

Dirk snickered.

Professor Crane suppressed a chuckle. "And where do you usually take one off from?" 

Andrea said, "From the top, of course. Why?"

"We can make stacks in programs, using an array and a pointer." He swapped slides again.

"The stack pointer points to the number most recently pushed on the stack. If we pop one off, we read it from where the stack pointer is pointing and decrement the stack pointer. If we push another on, we increment the stack pointer and then store it where the stack pointer points." 

Pat seemed to be following along okay, I was pretty sure I was, Mike was hanging in there, George was not quite, and the rest of the class were showing various states of confusion. 

Professor Crane showed us a slide with the following demonstration code in BASIC, and walked us through the initialization, the push and pop subroutines, and the execution of the main part:

10 REM PUSH AND POP SUBROUTINES 20 DIM S(10) 30 LET T = -1 REM STACK POINTER 40 LET V0 = -9999 REM TOP OF STACK TEMPORARY 100 V0 = 10 110 GOSUB 1010 120 V0 = 20 130 GOSUB 1010 140 V0 = 30 150 GOSUB 1010 160 V0 = -9999 170 GOSUB 1110 180 PRINT "POPPED "; V0 190 GOSUB 1110 200 PRINT "POPPED "; V0 210 GOSUB 1110 220 PRINT "POPPED "; V0 1000 END 1010 REM PUSH SUBROUTINE 1020 IF T = 10 THEN GOTO 12OO 1030 T = T + 1 1040 S(T) = V0 1050 RETURN 1100 REM 1110 REM POP SUBROUTINE 1120 IF T = -1 THEN GOTO 1300 1130 V0 = S(T) 1140 T = T - 1 1150 RETURN 1200 REM 1210 REM PUSH ERROR 1220 PRINT "STACK FULL ERROR. CAN'T PUSH "; V0; "." 1230 STOP 1300 REM 1310 REM POP ERROR 1320 PRINT "STACK EMPTY ERROR. CAN'T POP." 1330 STOP

Then he showed us a printout of what running it produced:

POPPED  30
POPPED  20
POPPED  10 

We discussed the code for a few minutes, then he showed us demonstration code in Pascal, again walking us through the initialization, pop function, push procedure, and the main execution:

program stackdemo;

const limit = 10;

var

  stack: array[0 .. limit] of Integer;
  tos: Integer;
  errorcode: Integer;

procedure push( value: Integer );
  begin
    if tos < limit then
      begin
        tos := tos + 1;
        stack[ tos ] := value;
      end
    else
      begin
        errorcode := 1;
        writeln( 'Stack full ', errorcode, '. Can''t push ', value, '.' )
      end
  end;

function pop: Integer;
  begin
    if tos >= 0 then
      begin
        pop := stack[ tos ];
        tos := tos - 1;
      end
    else
      begin
        errorcode := 2;
        writeln( 'Stack empty ', errorcode, '. Can''t pop.' );
        pop := -9999
      endfc
  end;
 
begin
  TOS := -1;
  errorcode := 0;
  push( 10 );
  push( 20 );
  push( 30 );
  writeln( 'Popping ', pop );
  writeln( 'Popping ', pop );
  writeln( 'Popping ', pop );
  if errorcode <> 0 then
    writeln( 'errorcode: ', errorcode );
end.

The output was essentially the same as the output of the BASIC demo code:

Popping 30
Popping 20
Popping 10

Becky raised her hand. "Can I see that slide that shows the stack of plates and the, uhm, number stack again?" 

Professor Crane grinned some more as he swapped slides.

Becky thought for a moment, then asked, "Why? uhm, ... in the subroutines, you're only adding one or subtracting one, but the picture of the array shows, what is that? They're all even numbers. That's adding two. Why?"

"Very good," Professor Crane adjusted his slide. "Very observant, Becky. Pat, what do you have to say about this? Joe? Mike?"

The three of us exchanged looks, then Pat nodded to Mike. "What do you think, Mike? You got this?"

He shook his head.

She turned to me, and I lifted my fist, showing gu. "Rock, scissors, paper."

She gave me a quizzical look.

"No jung? Toss a coin, then?" I reached for my pocket.

"You start."

I refrained from pulling out my coin purse. "I'm not sure I can make it make sense."

"Me neither."

I nodded my head in resignation. "Well, okay." I turned to Becky and said, "Address versus index. The picture of the stack array is showing addresses in memory, but the code uses numeric indexes into the array."

Pat nodded. Out of the corner of my eye I saw the light come on in Mike's eyes. 

Becky's eyes reflected something that looked like the beginning of understanding.

Pat asked, "Integers in Pascal are like, two bytes in memory, Professor Crane?" 

"Yep. Well, with the compiler we have, yes."

Becky's eyes lit up, then the flame flickered and was replaced again by doubt. She hesitated, then asked, "So  one in Pascal is like two in assembler or memory or whatever that is?"

"Right!" Mike exclaimed. "Pascal converts the index number to an address. Multiplies the index by the size of the elements and adds the base address of the array." He paused, then continued. "But ... the BASIC array is going to be more than two, right? BASIC variable are floating point, not integers."

Now Becky looked more confused.

Professor Crane nodded in agreement. "Yep. Most BASICS don't have small integer variables. Just floating point, and BASIC floating point numbers tend to be five bytes each, as a tradeoff between memory requirements and range."

Becky hesitated again before asking, "So the index would be multiplied by five instead of two?"

Professor Crane smiled and nodded in confirmation.

Becky responded with a proud smile of her own.

After a few more minutes of discussion, Professor Crane looked at me and raised his eyebrows.

"What?"

He grinned again. "I thought I saw you doodling a few minutes back.

I glanced at the code I had jotted down before the lesson had gotten interesting. 

"Not really."

He looked disappointed. "So you haven't converted the Fibonacci program to 68000 assembler while we've been discussing how local variables work? Or worked out an assembler version of the stack demonstration code?"

"I got interested in class."

That got a laugh from most of the students.

"Oh."

I scratched behind my ear. "Besides, the stack demonstration wouldn't really be all that interesting."

"Why not?"

"68000 machine language has push and pop built in."

"Built-in, huh?"

"Well, I guess they don't test for overflow or underflow."

"No?"

"I guess the CPU architects leave stack bounds checking to the memory management hardware."

He raised his eyebrows and nodded. "Yes, most CPUs are like that, although I hear Intel's iAPX 432 might be different. So you don't want to show us what the demonstration program would look like in 68000 assembler?"

I set my chin to the right and my mouth the left,  and pinched my nose before scratching my chin. "With no bounds checking?"

"Sure."

"Okay." I stood and went to the whiteboard, and wrote out the following, pausing at moments for thought, but not commenting vocally:

STKSZ EQU 11

SSTACK DS.W STKSZ
PSTACK DS.L 64
RSTACK DS.L 64

MESSAGE DC.B 'Popping '
DC.B 0 ; end of string START MOVE.L #RSTACK+STKSZ*4,A7 ; for return addresses MOVE.L #PSTACK+STKSZ*4,A6 ; for the parameters MOVE.L #SSTACK+STKSZ*2,A5 ; for the demonstration stack * Main code
* Push 16 bit values on 32 bit stack: MOVE.W #10,-(A5) CLR.W -(A6) ; High word first in memory. MOVE.W #20,-(A5) CLR.W -(A6) ; High word MOVE.W #30,-(A5) CLR.W -(A6) ; High word * Pop and print MOVE.L #MESSAGE,-(A6) BSR PSTRING MOVE.L (A5)+,-(A6) BSR PINT BSR PCRLF MOVE.L #MESSAGE,-(A6) BSR PSTRING MOVE.L (A5)+,-(A6) BSR PINT BSR PCRLF MOVE.L #MESSAGE,-(A6) BSR PSTRING MOVE.L (A5)+,-(A6) BSR PINT BSR PCRLF RTS

Professor Crane frowned. "Your stacks are all upside down."

"Most CPU stacks are, aren't they?"

He turned to the class. "Can any of you guys tell what his code does?"

Even Pat was a little bemused. "Can you make it look more like the Pascal and BASIC demonstration code?" she asked.

I grumbled jokingly as I turned back to the board, erased it, and started rewriting, vocalizing both the code and the comments:

* Fully emulating the demonstration stack:
SSTKSZ EQU 11	; Software stack
SSTACK DS.W SSTKSZ	; of 16-bit integers
SSTKPTR DS.W 1	; Don't even need 16 bits.
* Planning on doing it upside-up, with base in A5.

"I could keep the index in D7, too. But I guess we want to see me manipulate the stack pointer as an index, anyway."

ERRORCODE DS.L 1

STKSZ EQU 64
PSTACK DS.L STKSZ ; parameter stack
RSTACK DS.L STKSZ ; return stack
* Both are traditional pushdown.

"Sixty-four levels ought to be enough for whatever the library and OS need."

"Two CPU stacks?" Professor Crane asked.

"I think I like two stacks."

MESSAGE_STR
 DC.B 'Popping '
 DC.B 0

"Not counted strings?" Professor Crane asked.

"Seems easier this way. There's no compiler to keep track of the count for me, and this way I don't need to keep track by hand."

"Makes sense."

PUSHERRMSG_01
 DC.B 'Stack full. ERROR '
 DC.B 0
PUSHERRMSG_02
 DC.B ': Can''t push '
 DC.B 0
PUSHERRMSG_03
 DC.B '.'
 DC.B 0

I lifted my marker. "Yeah, that's a lot of bits of the message spread out. Oh, well."

"No formatted I/O in the library code?"

"Well, then I would have to explain the library code."

"Ah. Less to explain this way." Professor Crane seemed satisfied.

I continued:

PUSHERR
 MOVE.L #PUSHERRMSG_01,-(A6)
 BSR PSTRING
 MOVE.L ERRORCODE,-(A6)
 BSR PINT
 MOVE.L #PUSHERRMSG_02,-(A6)
 BSR PSTRING
 BSR PINT ; value waiting on parameter stack
 BSR PCRLF
 MOVE.L #PUSHERRMSG_03,-(A6)
 BSR PSTRING
 JMP ERREXIT

"Tedious, but nothing difficult to understand. Put what we want to print on the parameter stack, call the routine to print it."

* Upside-up stack!
* A5 is demonstration stack base.

"Oh, I should probably have put the base in a variable, too. But I'm doing it this way, now." 

"Go ahead and show us how it turns out."

PUSH
 MOVE.W SSTKPTR,D7
 CMP.W #STKSZ,D7
 BHS PUSHERR ; unsigned

"That loads the stack pointer, and then compares it to the size of the stack. By using an unsigned compare, we can skip testing the lower bound of zero. But the Pascal source didn't check the opposite end, anyway."

"True."

 ADD.W #1,D7
 MOVE.W D7,SSTKPTR ; update pointer
 ASL.W #1,D7 ; adjust index for 16-bit array

"Arithmetic shifting left one is the same as multiplying by two." 

Professor Crane added, "Becky, there's your conversion between index and offset to an address." 

"Oh-kay." But she didn't really sound all that okay, yet.

 MOVE.L (A6)+,D0 ; pop 32 bits of parameter

"A6 in paranthesis says A6 points to the source value. The plus after says that the CPU updates the pointer after the move, by adding the size of what it moved to D0. The parameter stack that A6 points to is 32 bits wide, to save code. That's four bytes, so A6 gets four added to it."

 MOVE.W D0,(A5,D7.W) ; store 16-bit integer

"The value stored was only our 16-bit integer, so we only need to store two bytes. And that funky looking index expression in the parenthesis here says that A6 has the base address of the array, and D7 has the offset -- the index we multiplied by two up there. The CPU adds the base and the offset to get the address of the element of the array to store it in."

Becky hesitated before saying, "A6 plus D7 is the address where it's stored?"

"Yeah." 

"What's that period double-u mean?"

"W stands for word, and a 16-bit integer in 68000 assembler is called a word. An 8-bit integer is B for byte, and a 32-bit integer is L for long."

"Hmm. Maybe I'm seeing this."

"Great." I continued.

 RTS

"The return from subroutine instruction pops the return address from the return stack and loads it into the program counter, which is what Motorola calls the instruction pointer." I paused. 

"And the pop routine just reverses this process."

POPERRMSG_01
 DC.B 'Stack empty. ERROR '
 DC.B 0

"Error message can't tell anyone about a value that doesn't exist, so the message strings are a little simpler."

POPERRMSG_02
 DC.B ': Can''t pop.'
 DC.B 0
*
POPERR
 MOVE.L #POPERRMSG_01,-(A6)
 BSR PSTRING
 MOVE.L ERRORCODE,-(A6)
 BSR PINT
 MOVE.L #POPERRMSG_02,-(A6)
 BSR PSTRING
 BSR PCRLF
 JMP ERREXIT
*
POP
 MOVE.W SSTKPTR,D7 ; Not testing for too high.

"On the 68000, loading a data register sets the condition codes, so we already know if it's zero or minus. Minus would be a stack underflow. And will ignore testing against the other end of the stack here."

 BMI POPERR
 ASL.W #1,D7 ; adjust index for 16-bit array
 MOVE.W (A5,D7.W),D0
EXT.L D0 ; Make it 32-bit

"We'll extend the sign bit, since we'll be passing it to library functions."

 MOVE.L D0,-(A6)
 SUB.W #1,SSTKPTR ; update pointer

"Conveniently, the 68000 allows us to add that to the index in memory, so we don't have to keep an extra copy in a register." 

"Like you don't have enough extra registers to keep a copy," Professor Crane joked.

"Heh. Plenty of data registers we're not using."

 RTS

START
* Runtime.

"First, we set up the return stack pointer so we can do subroutine calls, and the parameter stack pointer so we can pass parameters."

 MOVE.L #RSTACK+STKSZ*4,A7 ; for return addresses
 MOVE.L #PSTACK+STKSZ*4,A6 ; for the parameters 

"Wait a minute." Professor Crane stopped me.

"Yeah?"

"Oh, yeah. You said you like two stacks."

"I think so."

"Does the 68000 have instructions to support stack frames?"

"There's a link instruction and an unlink instruction."

"Hmm. Well, go ahead."
 MOVE.L #SSTACK,A5 ; emulating the demonstration stack
 MOVE.L #0,SSTKPTR ; demonstration stack index

Becky muttered, "Okay, there's the base of that array, and the index." 

I nodded and continued writing:

* Main code:
* push values
 MOVE.W #10,-(A6)
 CLR.W -(A6) ; High word first in memory.

"Woops. That should also be sign-extended." I thought for a minute, erased the last line, and changed the line before it:

 MOVE.L #10,-(A6)

Pat asked, "The 68000 is most significant bit first?" 

"Yeah."

"Isn't that inefficient?"

"Ask the engineers. It sure seems easier for human eyes to read." 

I have much stronger arguments about byte order now, but we don't want to interrupt the story too much.

 BSR PUSH
 MOVE.L #20,-(A6)
 BSR PUSH
 MOVE.L #30,-(A6)
 BSR PUSH
* Pop and print
 MOVE.L #MESSAGE,-(A6)
 BSR PSTRING
 BSR POP
 BSR PINT
 BSR PCRLF
 MOVE.L #MESSAGE,-(A6)
 BSR PSTRING
 BSR POP
 BSR PINT
 BSR PCRLF
 MOVE.L #MESSAGE,-(A6)
 BSR PSTRING
 BSR POP
 BSR PINT
 BSR PCRLF
 RTS 

When I turned around,  only Daren, Andrea, and Alex still looked lost.

"So, how would that change if you used stack frames?" Professor Crane's eyebrows were raised.

"On a single stack?"

"Most system engineers don't want to go to the trouble of supporting two stacks."

"I sure don't know why. But with something this simple, there really isn't a reason for frames at all."

"That might make it easier to understand frames, if they're there."

 "Maybe. But I don't think I remember exactly what the link and unlink instructions do. How about if I just show where we can save a stack frame pointer in this code?"

"You can?"

"Pretty simple, really. On routine entry, you just push a copy of the parameter stack pointer, probably on the return stack to keep the parameter stack clean and give the frame pointer some protection. Then just remember to pop it on exit."

I wrote a fragment on the board:

SUBROUTINEA
 MOVE.L A6,-(A7) ; Mark frame.
 ...
 MOVE.L (A7)+,A6 ; Force restore frame.
 RTS 

"Or, since the parameter stack is balanced, instead of loading the parameter stack pointer back, just  drop the saved frame pointer off the return stack:"

SUBROUTINEA
 MOVE.L A6,-(A7) ; Mark frame.
 ...
 ADD.L #4,A7 ; Drop frame.
 RTS 
"Either way, you can load the frame pointer from the return stack whenever you need it."

"How do you tell the parameters of a recursive call from those of a non-recursive call?"

I had to think for a moment. "Maybe you have to mark the frame before you call the subroutine. Then, I guess, when a routine calls itself recursively, it would do something else:"

ROUTINEA
... MOVE.L A6,-(A7) ; Mark frame.
BSR RECROUTINE ADD.L #4,A7 ; Drop frame.
... RTS
*
RECROUTINE
...
MOVE.L 4(A7),A4 ; Saved PC is top. MOVE.L A4,-(A7) ; Mark old frame.
BSR RECROUTINE ADD.L #4,A7 ; Drop frame.
... RTS

 Professor Crane looked at my code with a puzzled expression. "That looks like it might work, actually."

The bell rang.

"Okay, we'll continue this next class. Homework is to write the Fibonacci series code recursively in BASIC."

Groans echoed through the room.

"I've given you enough tools, I think you can do it. Try, anyway. And, Joe, can you look up the link and unlink instructions and bring some code using them, too?"

"Uh, oh, okay. Sure." 

(Could I have produced the 68000 assembler code above during my first year back from Japan? I'm not confident I could. But the me in this story has to be able to.)

Chapter 3.7: 
TOC

[Currrent backup at https://joel-rees-economics.blogspot.com/2020/01/bk-33209-school-parameter-stack.html.
Developed February to April 2021, notes at https://joel-rees-economics.blogspot.com/2020/01/notes-33209-school-basic-vs-pascal-vs.html.
Extracted and expanded from https://joel-rees-economics.blogspot.com/2020/01/bk01-33209-school.html.
Earlier backup at https://joel-rees-economics.blogspot.com/2020/01/bk-33209-school.html.]

33209: School -- BASIC vs. Pascal vs. Assembler

Chapter 3.4: School -- Shoe Sizes, Flowcharting, and Pseudo-code

Chapter 3.5: School -- BASIC vs. Pascal vs. Assembler

Professor Crane set aside the slides he had been using to explain the simple address book program that would be our next assignment and picked up another set. 

"I'm sure y'all all want to talk about Pascal some more."

Scattered chuckles and groans greeted the pronouncement.

"Well, we're going to talk a little more about Pascal today so we can talk about something Professor Bright and I are studying, called structured programming." He paused.

"There are dialects of BASIC in existence which don't use line numbers. And you can write programs in those without using a GOTO."

"Cool."

"Wow!"

"Help?"

"Why not just move to Pascal instead of ruining BASIC?"

I was not one who said any of the above. I think my response was, "So, these versions of BASIC look kind of like Pascal?"

"Kind of."

"How does that even work?" asked Becky.

"Well, let's talk about structured programming." He waited for the chatter to stop. "In BASIC, you can write code that looks like a plate of logical spaghetti with strands of program flow going all over the place and getting all tangled up in a mess. In Pascal, it's a lot harder to write spaghetti code. But even in BASIC, you can usually untangle that spaghetti into more understandable sequences of just a few kinds of fundamental elements." He put a slide on the overhead projector.


"This is one fundamental element, the block. And on the right is a sequence of blocks."

Lisa asked, "Is a block like a line of BASIC?"

"Or of Pascal. A line or a group or lines can be a block. The idea is that together they perform a single function. And you can treat them like a single block. Ideally, you start in at the top of the block and end at the bottom. Pascal also allows you to explicitly declare a block using the BEGIN and END statements."

He waited for a moment so we could copy the slide into our notes. Then he traded the slide for another.

"This is the decision, conditional, or branch."

"It's the BASIC IF statement," asserted Daren.

"Very good. It gets constructed with the IF statement, and often requires GOTOs in the usual dialects of BASIC. The GOTO will jump around the false and true blocks for he the condition George, can you write us an example on the board?"

George went to the board and wrote:

1000 REM TWO-WAY DECISION
1010 IF V1 = V2 THEN GOTO 1100
1020 REM FALSE BRANCH
1030 A1=B1
1040 REM ETC.
1090 GOTO 1200
1100 REM TRUE BRANCH
1110 B1=A1
1120 REM ETC.
1190 REM END OF BLOCK
1200 REM SOMETHING ELSE CONTINUES FROM HERE.

Instead of copying what he wrote, I doodled on the back of a program listing:

* 2-way decision/branch (conditional)
* IF V1 = V2, 32-bit integer V1 and V2
	MOVE.L vV1,D0
 	SUB.L  vV2,D0
 	BNE IFNEV1V2  ; Inverted test.
* LET A1 = B1
MOVE.L vA1,vB1 ; true branch * etc. BRA IFDONEV1V2 IFNEV1V2 ; false branch * LET B1 = A1 MOVE.L vB1,vA1 * etc. * end of block IFDONEV1V2 * continues from here

Several of the students were still busily taking notes when George sat down. 

Professor Crane asked for questions, but the students who were lost just gave him blank looks. So he continued, "In Pascal, that would look like this." He took out a clean slide and put it on the projector, and wrote:

{ Two-way decision }
  IF V1 = V2 THEN 
  BEGIN
    { True branch! }
    B1 := A1
    { Etc. }
  END
  ELSE
  BEGIN
    { False branch. }
    A1 := B1
    { Etc. }
  END
  { Something else continues from here. }

"Why do I have the false and true branches reversed here from the BASIC code?"

Lisa suggested, "Because the test will make a jump, and you jump to the true branch, but, uhmm," she thought, then continued slowly, "... just let the program flow into the false branch?"

Becky exclaimed, "Oh, I get it." She hesitated. "I think."

"Good. Anyone not getting it?"

No response.

Professor Crane stood up and walked around the room, checking students' notes. He stopped at my desk. "May I?"

I looked up at him questioningly. 

"Take a look at your assembler notes. Is this 68000 assembler?"

"Yeah. I didn't want to think too hard about integer size." I held the page up, and he accepted it.

"Mind putting this up on the board to show the class?"

"Sure. I mean, no. No problem." I stood and went to the board, repeating the doodled code from memory.

Professor Crane pointed to the first line. "Is this a comment?"

"Yeah. Comment lines start with asterisk in Motorola assemblers."

"Interesting." He pointed to the third line. "Move dot 'L'?"

"Long is 32 bits. Dot 'W' would be word, or sixteen bits. Dot 'B' would be byte, or eight bits."

"So that's a 32-bit integer move. 8086 only does 16-bit. You put 'v' in front of the variable names?"

"Otherwise, A1 would, uhm, the name of variable A1 would conflict with the name of address register A1."

"I see. Okay, Intel syntax has the target first, as move to target from source. I guess Motorola syntax is more English-like, move from source to target?"

"Yeah. Data register zero is the target of the first move. I'm using subtract for the compare in the next line because," I hesitated here, "the compare is just a subtract that doesn't store it's result, and I'm pretty sure it's the same order as subtract, but I didn't want to think about it. Not that it matters here, since we're only testing equality."

Professor Crane snorted a chuckle and shook his head. "How many registers does the 68000 have?"

"Eight data registers, D0 through D7, and eight address registers, A0 through A7. Ehh, plus a second A7. A7 is the stack pointer for subroutine calls, and there's a user A7 and a system A7." 

"That's a lot of registers. Does it have an accumulator?"

"Any data register can be an accumulator."

He raised his eyebrows and turned back to the listing. "Okay, 'BNE' is?"

"Branch if not equal. Not equal to zero. Inverted condition so I could write the true branch first. Branch to," I spelled it out: "'I-F-N-E-V-1-V-2'. That label is supposed to mean 'If not equal V1 and V2'."

"You made the label up."

"Yep." 

"And labels are?"

"Machine language has addresses instead of line numbers, but when you edit code, the code moves around, so the addresses change. So the assembler lets you give a location a name, and then the assembler figures out the address for you."

"So it's like a line number, but different."

"Right."

"Okay. Is that a memory-to-memory move in the next instruction, direct, without using a register?"

"Yeah. Target is the second argument."

"Again, opposite Intel assembler order. And that is not a reference to women's underwear in the next instruction?"

There was a wave of snickers and titters.

"Branch always," I answered apologetically. "I think I would have just used 'BR' or written it out 'BRANCH', but I'm not the one who made up the mnemonics."

Professor Crane nodded. "I hope none of the women in the class are offended. Macros would allow that instruction to be renamed, by the way."

Lisa cleared her throat. "How nice of them." She and Pat exchanged looks.

Pat shrugged. "I wish we didn't have to put up with immature male engineers. It sure isn't an ideal world."

Dirk let out a horse laugh. "Yer im-mah-choor, Joe."

Lisa gave him a glare. 

"Okay, okay, maybe I'm a little immature, too, sometimes." Dirk was still laughing, but not out loud. "How about you, Joe?"

I rolled my eyes and shrugged. "Probably not as mature as I ought to be all the time."

"So we'll both try to grow up?" He grinned at me.

"Yeah."

Lisa sniffed and turned away. Since she was between Dirk and me, she was now looking at me. She tried to keep a straight face, then broke out laughing when I shrugged apologetically again. She looked back to Pat and said, "We're holding these guys to their promise, right?" 

Pat nodded, her face showing mixed feelings.

"We'll work on it." I reached over and bumped fists with Dirk.

"Is one- or two-way branching all there is in structured programming?" Mike asked.

Professor took the cue. "There is also a case construct, but it can be built from these two. We can look at it later. I want us to look at loops now." 

"Wait," Becky hold up her hand. "Don't you need more branches to surround the false and true blocks?"

I turned back to the whiteboard and pointed to the code between the branch not equal and the branch always. "Since the test is inverted, the false case branches over the true case block." I pointed to the branch always. "The true case ends by branching over the false case block to the label 'IFDONEV1V2'. But, since that label is just the address of the instruction after the false case block, the program flow naturally joins back together there without a branch."

Becky still looked a little puzzled, but she nodded.

I sat down.

Professor Crane had swapped slides while we were discussing the program flow.

"Here we are. These are the two loops generally discussed in structured programing."

Mike asked, "Is there a mid-test loop?"

Professor Crane pulled his mouth to the side.

I looked up and added, "As in a general loop with a block before and after the test?"

Mike glanced at me and nodded. 

Professor Crane still hesitated.

Mike stood. "Can I draw out what I mean?"

"Go for it." Professor Crane held out a marker.

Mike took it and drew this:

Professor Crane nodded thoughtfully. "That's a general loop. There are languages that have such loops built-in, but most structured programming practice suggests against it, from what I understand. Pascal doesn't have one."

Mike turned back to the board and wrote out example BASIC code for the loop to the side:

2000 REM LOOP STARTS HERE
2010 REM PRE-TEST BLOCK
2020 A=B+C
2030 REM ETC.
2100 IF A=E THEN GOTO 2200
2110 REM POST-TEST BLOCK
2120 A=-B-C
2130 REM ETC.
2190 GOTO 2000
2200 REM PROGRAM CONTINUES FROM HERE

"And the pre-test and post-test loops would just have one of those blocks empty," he commented as he put the marker back in the tray.

Alex complained, "What does that code even do?"

Mike frowned and cocked his head. "It's just example code."

"Just enough," I looked up from my assembly language doodling, "to see the connection between the BASIC and the flowchart." 

I had this scribbled down at this point:

LOOPSTART
* Pre-test block
* A=B+C
MOVE.L vB,D0
ADD.L vC,D0
MOVE.L D0,vA
* Etc.
* IF A=E THEN GOTO exit
CMP.L vE,D0 ; D0 - vE
BEQ LOOPEND
* Post-test block
* A=-B-C
CLR.L D0
SUB.L vB,D0
SUB.L vC,D0
MOVE.L D0,vA
* Etc.
LOOPEND 

Mike frowned and turned back to the whiteboard. He picked up the eraser, but Professor Crane said, "We have lots of whiteboard space."

So he put the eraser down and started writing more code in an open spot:

2000 REM GET NEXT SHOE SIZE
2010 INPUT "SHOE SIZE ('Q' FOR QUIT):"; R$
2020 IF LEFT$(1) = "Q" THEN GOTO 2200
2030 R = VAL( R$)
2040 REM ...
2200 GOTO 2000

"How's that?"

Professor Crane nodded and said, "Looks more like real-world code."

Alex was still puzzled. "Isn't that just testing at the top?"

Professor Crane cocked his head. "Is the input statement part of the test?"

Alex shook her head. "I guess not?"

I interjected, "Depends on how you look at, right, Professor Crane?"

He chuckled without much mirth before responding. "And on how you write the program. It is possible to have an input procedure that returns a boolean yes or no."

Alex raised her hands in despair. "Please don't put this on the test."

Professor Crane grinned. "You know I like to make y'all think."

The whole class groaned.

"But I'll make sure there's enough information to answer it, if I do." 

He pulled another slide out. "Anyway, after we talk a bit more about the basics, I can show you all how to do Mike's example with a conditional inside a pre-test or post-test loop." 

With that, he proceeded to use the remainder of the period to lead the class through comparing the structured flow elements in Pascal and BASIC, and, borrowing more of my doodling, assembly language. Our assignment was a simple address book program using BASIC DATA statements to build separate arrays of names, addresses, and phone numbers.

(Maybe I don't need to say this again, but I will. The Joe of this novel is way ahead of the Joe of the real world. I had only begun to pick up the rudiments of 6800 assembler during the first semester back from my mission. Translating BASIC or Pascal to 68000 assembler during a lecture would have been me at least a year later, probably two. 

And I wasn't that good with banter. Still not, really.)

TOC

[Current backup at https://joel-rees-economics.blogspot.com/2020/01/bk-33209-school-basic-vs-pascal-vs-assembler.html.
Developed February and March 2021, notes at https://joel-rees-economics.blogspot.com/2020/01/notes-33209-school-basic-vs-pascal-vs.html.
Extracted and expanded from https://joel-rees-economics.blogspot.com/2020/01/bk01-33209-school.html.
Earlier backup at https://joel-rees-economics.blogspot.com/2020/01/bk-33209-school.html.]

3809/2801: ALUs, Register Indirect Review, Role Playing the 6800

2801 ALUs, Register Indirect Review, Role Playing the 6800 Motorola M6800 EXORcises T...