Sunday, July 14, 2024

ALPP 01-06 -- Global Constants on the 6800, 6801, 6809, and 68000

Global Constants on the 6800, 6801, 6809, and 68000

(Title Page/Index)

 

So, now we have working environments set up for the 6800, 6809, 6801, and 68000,  and have taken a look at summing up a few small integer constants buried in the code on each of these processors.

Do you think having a list of numbers buried in the code might be a little clumsy? Just a little bit?

It is. Usually.

There are several ways to separate the numbers from the code that adds them. Let's take a look at one here, a way which we will call using global constants.

There are three related topics we will introduce here, in the process.

  • labels,
  • lists in memory
  • absolute addressing

And, while we're at it, you might want to think about object code size and execution time. We haven't taken up all the tools necessary to think about such things, but you might want to, anyway.

First, lets get the constants out of the code. 

In Motorola's 680X assemblers, the usual way to define a constant byte-sized integer is to use the FCB directive. You may think FCB stands for File Control Block, but in this context it means Form Constant Byte:

	FCB	8

We do not use "FCB #8" for two reasons. Well, three. One is that this is no longer immediate addressing. The other is that FCB is not an instruction for the microprocessor. It's a directive to the assembler. And the other other reason is that the assembler will complain if you do. Because of the first two reasons. And I promise this will make more sense later.

But it's not enough to have that small constant out there in memory somewhere. We need some way for the code to reference it. So we will give it a label, maybe call it BYTE8 (because it sounds cool or something):

BYTE8	FCB	8

You might remember the label START at the beginning of the code in our previous examples? It's basically the same thing in a slightly different context. 

This is quite literally just a label, a name by which a particular address in memory can be referenced.

Okay, here's the entire summing code for the 6800, using the separate constants:

ENTRY	JMP	START
*
BYTE8	FCB	8
BYTE5	FCB	5
BYTE2	FCB	2
BYTE7	FCB	7
BYTE4	FCB	4
*
START	LDAB	BYTE8
	ADDB	BYTE5
	ADDB	BYTE2
	ADDB	BYTE7	
	ADDB	BYTE4
	NOP
DONE	NOP	

Those asterisks at the start of those two lines are Motorola's way to show that the entire line is a comment. In this case, it's to make a deliberate empty line in the source code, to separate code from constants. It has zero effect in the object code.

That's a JuMP at label ENTRY. It jumps over the constants.

Is it necessary? 

Good question. 

:-)

Get a running EXORsim debugging session:

$ ./exor --mon
Load facts file 'facts'
'exbug.bin' loaded.
  EXBUG-1.1 detected
'mdos.dsk' opened for drive 0 (double sided)

OSLOAD...

Hit Ctrl-C for simulator command line.  Starting simulation...

>         0 A=00 B=00 X=0000 SP=00FF ------          0020: B6 E8 00 LDA E800                 

6800 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help'
%

Start an assembly at address $1000 and paste it in. Remember, right-click-paste to paste into the shell, because the shell thinks Ctrl-V means something else:

% a 1000
1000: ENTRY	JMP	START
1003: *
1003: BYTE8	FCB	8
1004: BYTE5	FCB	5
1005: BYTE2	FCB	2
1006: BYTE7	FCB	7
1007: BYTE4	FCB	4
1008: *
1008: START	LDAB	BYTE8
Address at 1001 set to 1008
100b: 	ADDB	BYTE5
100e: 	ADDB	BYTE2
1011: 	ADDB	BYTE7	
1014: 	ADDB	BYTE4
1017: 	NOP
1018: DONE	NOP	
1019: 

Disassemble it to see how it went:

% u 1000
1000: 7E 10 08            JMP $1008
1003: 08                  INX
1004: 05                  ???
1005: 02                  ???
1006: 07                  TPA
1007: 04                  ???
1008: F6 10 03            LDB $1003
100B: FB 10 04            ADDB $1004
100E: FB 10 05            ADDB $1005
1011: FB 10 06            ADDB $1006
1014: FB 10 07            ADDB $1007
1017: 01                  NOP
1018: 01                  NOP
1019: 00                  ???
101A: 00                  ???
...

Ackkkkkk! Where are the constants?!?!?!?!? And what is this INX and TPA and ????

If you don't jump over the constants, the processor will see that $08 as the op-code for the INcrement X instruction, and the $07 as the Transfer Processor status to A instruction. So that's what the disassembler shows you. And 5, 2, and 4 are not defined instructions, so the disassembler prints question marks.

And the processor, who knows what it would do?

(Interested geeks have researched this question. You can look it up if you are so inclined, but most undefined op-codes aren't all that interesting on the 6800.)

So. Maybe we do need that JMP instruction. Yes, we do. Sort of.

Now, since we are using the interactive debugger, we could just use the step or continue debugger command to tell it to start at address $1008. In fact, we could. We know that. 

But how does an operating system know that? How does someone who has neither the source code nor a debugger know what address to start at? I mean, without the source, here's all you have:

% d 1000
1000: 7E 10 08 08 05 02 07 04  F6 10 03 FB 10 04 FB 10 ~...............
1010: 05 FB 10 06 FB 10 07 01  01 00 00 00 00 00 00 00 ................
1020: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................
...

So, on the one hand, no the JMP is not exactly necessary. On the other hand, it is a useful convention. We will use it, at least until we have something better.

So, set a breakpoint, turn trace on, and watch it do its stuff:

% b 1018
Breakpoint set at 1018
% t on
% c 1000

          9 A=00 B=1A X=0000 SP=00FF ------ ENTRY    1000: 7E 10 08 JMP 1008  EA=1008(START) 
         10 A=00 B=1A X=0000 SP=00FF ------ START    1008: F6 10 03 LDB 1003  EA=1003(BYTE8) D=08 
         11 A=00 B=08 X=0000 SP=00FF ------          100B: FB 10 04 ADDB 1004 EA=1004(BYTE5) D=05 
         12 A=00 B=0D X=0000 SP=00FF ------          100E: FB 10 05 ADDB 1005 EA=1005(BYTE2) D=02 
         13 A=00 B=0F X=0000 SP=00FF ------          1011: FB 10 06 ADDB 1006 EA=1006(BYTE7) D=07 
         14 A=00 B=16 X=0000 SP=00FF H-----          1014: FB 10 07 ADDB 1007 EA=1007(BYTE4) D=04 
         15 A=00 B=1A X=0000 SP=00FF ------          1017: 01       NOP                      

Breakpoint!
>        16 A=00 B=1A X=0000 SP=00FF ------ DONE     1018: 01       NOP                      

6800 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help'
% 

And we can see it adding those up in the B accumulator.

The 6801 version will be pretty much exactly the same, but go ahead and change directories to where you built my 6801-enabled version of EXORsim and run a session to prove it to yourself:

$ ./exor --6801 --mon
Load facts file 'facts'
'exbug.bin' loaded.
'mdos.dsk' opened for drive 0 (single sided)

Hit Ctrl-C for simulator command line.  Starting simulation...

>         0 A=00 B=00 X=0000 SP=FF8A ------ OSLOAD   E800: 8E FF 8A LDS #$FF8A                Load OS

Type 'help'
%                                                                                                         
% a 1000
1000: ENTRY	JMP	START
1003: *
1003: BYTE8	FCB	8
Huh?: BYTE5	FCB	5
% 05: BYTE2	FCB	2
% 06: BYTE7	FCB	7
% 07: BYTE4	FCB	4
% 08: *
% 08: START	LDAB	BYTE8
% dress at 1001 set to 1008
% 0b: 	ADDB	BYTE5
% 0e: 	ADDB	BYTE2
% 11: 	ADDB	BYTE7	
% 14: 	ADDB	BYTE4
% 17: 	NOP
% 18: DONE	NOP	
% 19: 
% u 1000   
% 00: 7E 10 08            JMP $1008
% 03: 08                  INX
% 04: 05                  LSLD
% 05: 02                  ???
% 06: 07                  TPA
% 07: 04                  LSRD
% 08: F6 10 03            LDB $1003
% 0B: FB 10 04            ADDB $1004
% 0E: FB 10 05            ADDB $1005
% 11: FB 10 06            ADDB $1006
% 14: FB 10 07            ADDB $1007
% 17: 01                  NOP
% 18: 01                  NOP
% 19: 00                  ???
% 1A: 00                  ???
...

And so forth. 

One thing you'll notice is that, on the 6801, op-codes $05 and $04 are defined, whereas they are not on the 6800.

But we aren't using those, and even if you had a real 6801, even then, the timing would be the same. 

You may be wondering why I switched to using B to accumulate the sums here. As I mentioned in the chapter on getting started on the 6801, conventions on which accumulator was less significant switched between the 6800 and the 6809, and the 6801 follows the 6809 byte order in the D register instructions. But it follows the hard-wired 6800 stacking order during interrupts, to avoid too many surprises when re-using code from the 6800.

From here on out, we'll also be following the 6809 conventions on byte order where we can, not that you'll really notice it very often.

Now, let's see what happens on the 6809. In the first line of the code, change the LDAB to LDB:

ENTRY	JMP	START
...

The rest is the same source code.

Change back to Joe Allen's updated EXORsim and run a 6809 session. Paste in the code, making sure the LDAB is changed to LDB:

$ ./exor09 --mon
Load facts file 'facts09'
'exbug09.bin' loaded.
  EXBUG09-2.1 detected
'mdos09.dsk' opened for drive 0 (double sided)

OSLOAD...

Hit Ctrl-C for simulator command line.  Starting simulation...

>         0 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 --------            0020: 86 10        LDA #$10                   

6809 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help'
% a 1000
1000: ENTRY	JMP	START
later = 1001
1003: *
1003: BYTE8	FCB	8
1004: BYTE5	FCB	5
1005: BYTE2	FCB	2
1006: BYTE7	FCB	7
1007: BYTE4	FCB	4
1008: *
1008: START	LDB	BYTE8
Address at 1001 set to 1008
100b: 	ADDB	BYTE5
100e: 	ADDB	BYTE2
1011: 	ADDB	BYTE7	
1014: 	ADDB	BYTE4
1017: 	NOP
1018: DONE	NOP	
1019: 
% u 1000
1000: 7E 1008             JMP $1008
1003: 08 05               ASL $05
1005: 02 07               ??? $07
1007: 04 F6               LSR $f6
1009: 1003 FB             COM $fb
100C: 1004 FB             LSR $fb
100F: 1005 FB             ??? $fb
1012: 1006 FB             ROR $fb
1015: 1007 12             ASR $12
1018: 12                  NOP 
1019: 00 00               NEG $00
101B: 00 00               NEG $00
...

YIKES! 

Oh. The op-code map is a little different on the 6809, and our small constant integers are actually two-byte op-codes instead of one-byte -- which throws the disassembly off at address $1007.

Easy. We can note that the JMP at ENTRY is to address $1008, and disassemble from there:

% u 1008
1008: F6 1003             LDB $1003
100B: FB 1004             ADDB $1004
100E: FB 1005             ADDB $1005
1011: FB 1006             ADDB $1006
1014: FB 1007             ADDB $1007
1017: 12                  NOP 
1018: 12                  NOP 
1019: 00 00               NEG $00
101B: 00 00               NEG $00
...

Okay, the op-codes are a little bit different in places, but that doesn't hurt us.

% b 1018
Breakpoint set at 1018
% t on
% c 1000

          0 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 -------- ENTRY      1000: 7E 1008      JMP $1008                  
          1 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 -------- START      1008: F6 1003      LDB $1003   EA=1003(BYTE8) D=08 
          2 A=00 B=08 X=0000 Y=0000 U=0000 S=00FF P=00 --------            100B: FB 1004      ADDB $1004  EA=1004(BYTE5) D=05 
          3 A=00 B=0D X=0000 Y=0000 U=0000 S=00FF P=00 --------            100E: FB 1005      ADDB $1005  EA=1005(BYTE2) D=02 
          4 A=00 B=0F X=0000 Y=0000 U=0000 S=00FF P=00 --------            1011: FB 1006      ADDB $1006  EA=1006(BYTE7) D=07 
          5 A=00 B=16 X=0000 Y=0000 U=0000 S=00FF P=00 --H-----            1014: FB 1007      ADDB $1007  EA=1007(BYTE4) D=04 
          6 A=00 B=1A X=0000 Y=0000 U=0000 S=00FF P=00 --------            1017: 12           NOP                        

Breakpoint!
>         7 A=00 B=1A X=0000 Y=0000 U=0000 S=00FF P=00 -------- DONE       1018: 12           NOP                        

6809 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help'
%  

The 6809 version works exactly the same.

So we should be able to move on to the 68000. 

Except.

The 6809

      has

            something called PC-relative addressing.

OHHHHHHHH HORRORS!!!!

8-o

;->

Take a look at the disassembly in the code above. Where immediate mode addressing buried the actual constants in the code, you'll see the addresses of the constants buried in the code.

	LDB	BYTE8

becomes

F6 1003 

if you start the assembly at $1000.

But if you start the assembly at $1100, BYTE8 will become a label for $1108, and the object code will assemble as "FB 1103".

Which means that, once you have assembled the code, you can't just copy the code somewhere else to run it. You have to do something called relocation, where you dig through every address in the object code and adjust it for where it want it to end up.

Relocation is not as hard as it sounds. Sort-of. (Gurgle. Cough. Sigh.) Once you know what assumptions you can make. Which ...

We don't want to go there just yet.

PC-relative code can be moved without relocation math. Which is why it is called position-independent, or, sometimes, "relocatable". Erk.

We'll talk about this more later, but right now I think we should take a quick advance look at it.

Here's how PC relative code for the global constants looks for the code above:

ENTRY	JMP	START
*
BYTE8	FCB	8
BYTE5	FCB	5
BYTE2	FCB	2
BYTE7	FCB	7
BYTE4	FCB	4
*
START	LDB	BYTE8,PCR    ; address relative to PC
	ADDB	BYTE5,PCR
	ADDB	BYTE2,PCR
	ADDB	BYTE7,PCR
	ADDB	BYTE4,PCR
	NOP
DONE	NOP

Quit your EXORsim 6809 session and start a fresh one, and paste the above code in.

$ ./exor09 --mon
Load facts file 'facts09'
'exbug09.bin' loaded.
  EXBUG09-2.1 detected
'mdos09.dsk' opened for drive 0 (double sided)

OSLOAD...

Hit Ctrl-C for simulator command line.  Starting simulation...

>         0 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 --------            0020: 86 10        LDA #$10                   

6809 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help'
% a 1000
1000: ENTRY	JMP	START
later = 1001
1003: *
1003: BYTE8	FCB	8
1004: BYTE5	FCB	5
1005: BYTE2	FCB	2
1006: BYTE7	FCB	7
1007: BYTE4	FCB	4
1008: *
1008: START	LDB	BYTE8,PCR
Address at 1001 set to 1008
100b: 	ADDB	BYTE5,PCR
100e: 	ADDB	BYTE2,PCR
1011: 	ADDB	BYTE7,PCR
1014: 	ADDB	BYTE4,PCR
1017: 	NOP
1018: DONE	NOP
1019: 
% u 1000
1000: 7E 1008             JMP $1008
1003: 08 05               ASL $05
1005: 02 07               ??? $07
1007: 04 E6               LSR $e6
1009: 8C F8EB             CMPX #$f8eb
100C: 8C F6EB             CMPX #$f6eb
100F: 8C F4EB             CMPX #$f4eb
1012: 8C F2EB             CMPX #$f2eb
1015: 8C F012             CMPX #$f012
1018: 12                  NOP 
1019: 00 00               NEG $00
101B: 00 00               NEG $00
...
% u 1008 1008: E6 8C F8 LDB $1003,PCR 100B: EB 8C F6 ADDB $1004,PCR 100E: EB 8C F4 ADDB $1005,PCR 1011: EB 8C F2 ADDB $1006,PCR 1014: EB 8C F0 ADDB $1007,PCR 1017: 12 NOP 1018: 12 NOP 1019: 00 00 NEG $00 101B: 00 00 NEG $00 ...
% b 1018 Breakpoint set at 1018 % t on % c 1000 0 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 -------- ENTRY 1000: 7E 1008 JMP $1008 1 A=00 B=00 X=0000 Y=0000 U=0000 S=00FF P=00 -------- START 1008: E6 8C F8 LDB $1003,PCR EA=1003(BYTE8) D=08 2 A=00 B=08 X=0000 Y=0000 U=0000 S=00FF P=00 -------- 100B: EB 8C F6 ADDB $1004,PCR EA=1004(BYTE5) D=05 3 A=00 B=0D X=0000 Y=0000 U=0000 S=00FF P=00 -------- 100E: EB 8C F4 ADDB $1005,PCR EA=1005(BYTE2) D=02 4 A=00 B=0F X=0000 Y=0000 U=0000 S=00FF P=00 -------- 1011: EB 8C F2 ADDB $1006,PCR EA=1006(BYTE7) D=07 5 A=00 B=16 X=0000 Y=0000 U=0000 S=00FF P=00 --H----- 1014: EB 8C F0 ADDB $1007,PCR EA=1007(BYTE4) D=04 6 A=00 B=1A X=0000 Y=0000 U=0000 S=00FF P=00 -------- 1017: 12 NOP Breakpoint! > 7 A=00 B=1A X=0000 Y=0000 U=0000 S=00FF P=00 -------- DONE 1018: 12 NOP 6809 Monitor: Ctrl-C to exit, 'c' to continue, or type 'help' % q Bye

And, even though we only see the offsets in the code, the processor found the constants and was able to add them up.

We'll try more interesting things with this idea later. For now, file it away, and let's move on to the 68000 version of this. The code for absolute addressing first:

	OPT LIST,SYMTAB	; Options we want for the stand-alone assembler.
	MACHINE MC68000	; because there are a lot the assembler can do.
	OPT DEBUG	; We want the debugger to know our labels.
	OUTPUT
***********************************************************************
*	EVEN		; byte data doesn't have to be aligned.
ENTRY	JMP	START
*
BYTE8	DC.B	8
BYTE5	DC.B	5
BYTE2	DC.B	2
BYTE7	DC.B	7
BYTE4	DC.B	4
*
	EVEN		; But 68K code does have to be even aligned.
START	MOVE.B	BYTE8,D1
	ADD.B	BYTE5,D1
	ADD.B	BYTE2,D1
	ADD.B	BYTE7,D1
	ADD.B	BYTE4,D1
	NOP
DONE	NOP
* One way to return to the OS or other calling program
	clr.w	-(sp)	; there should be enough room on the caller's stack
	trap	#1			quick exit

Note that, instead of 

Form Constant Byte (FCB), 

the 68000 uses 

Define Constant Byte (DC.B).

Also notice that I've added a little formal quitting code at the end. And that's another something to talk about later.

I'm saving the source code as sumconst.s under in the working directory I made under the Hatari C drive emulation directory. In the above example, that would be

~/asmwork/share/hatari/C/primer/sumconst.s

And I'm assembling it with

$ vasmm68k_mot -Ftos -o SUMCONST.PRG -L sumconst.lst sumconst.s

Here's the listing it produces:

Sections:
00: "text" (0-24)


Source: "sumconst.s"
                            	     1: 	OPT LIST,SYMTAB	; Options we want for the stand-alone assembler.
                            	     2: 	MACHINE MC68000	; because there are a lot the assembler can do.
                            	     3: 	OPT DEBUG	; We want the debugger to know our labels.
                            	     4: 	OUTPUT
                            	     5: ***********************************************************************
                            	     6: *	EVEN		; byte data doesn't have to be aligned.
00:00000000 6006            	     7: ENTRY	JMP	START
                            	     8: *
00:00000002 08              	     9: BYTE8	DC.B	8
00:00000003 05              	    10: BYTE5	DC.B	5
00:00000004 02              	    11: BYTE2	DC.B	2
00:00000005 07              	    12: BYTE7	DC.B	7
00:00000006 04              	    13: BYTE4	DC.B	4
                            	    14: *
                            	    15: 	EVEN		; But 68K code does have to be even aligned.
00:00000008 123AFFF8        	    16: START	MOVE.B	BYTE8,D1
00:0000000C D23AFFF5        	    17: 	ADD.B	BYTE5,D1
00:00000010 D23AFFF2        	    18: 	ADD.B	BYTE2,D1
00:00000014 D23AFFEF        	    19: 	ADD.B	BYTE7,D1
00:00000018 D23AFFEC        	    20: 	ADD.B	BYTE4,D1
00:0000001C 4E71            	    21: 	NOP
00:0000001E 4E71            	    22: DONE	NOP
                            	    23: * One way to return to the OS or other calling program
00:00000020 4267            	    24: 	clr.w	-(sp)	; there should be enough room on the caller's stack
00:00000022 4E41            	    25: 	trap	#1			quick exit

If you know how to read the op-codes, you'll notice that the assembler seems to be doing something you're not expecting. Let's check.

Get Hatari running, Ctrl-Z to escape GEM and get a TOS (CP/M) shell, Alt-Pause to enter the debugger, use the mouse to bring up the host shell you started Hatari in, and set the breakpoint (b) to break when the CPU jumps to the TEXT segment, then do a continue (c) to return to the TOS (CP/M) shell:

CPU condition breakpoint 1 with 1 condition(s) added:
	pc = TEXT
-> Break only once, and delete breakpoint afterwards.
> c
Returning to emulation...

Invoke the assembled code in the TOS shell:

C:\primer>SUMCONST.PRG

Use the mouse to get back to the host shell where the debugger has taken the break and is waiting for you. Disassemble (d):

> d
(PC)
ENTRY:
00013d10 6006                     bra.b #$06 == $00013d18 (T)
BYTE8:
00013d12 0805 0207                btst.l #$0207,d5
BYTE4:
00013d16 0400 123a                sub.b #$3a,d0
00013d1a fff8                     illegal 
00013d1c d23a fff5                add.b (pc,$fff5) == $00013d13 [05],d1
00013d20 d23a fff2                add.b (pc,$fff2) == $00013d14 [02],d1
00013d24 d23a ffef                add.b (pc,$ffef) == $00013d15 [07],d1
00013d28 d23a ffec                add.b (pc,$ffec) == $00013d16 [04],d1
00013d2c 4e71                     nop 
DONE:
00013d2e 4e71                     nop 
00013d30 4267                     clr.w -(a7) [0000]
00013d32 4e41                     trap #$01
00013d34 0000 0000                or.b #$00,d0
00013d38 0000 0000                or.b #$00,d0
...

Didn't remember a BRAnch instruction?

My neither. That was supposed to be a JuMP.

It's getting confused trying to disassemble constants as code, so look at the target for the branch ($00013d18) and disassemble from there. Except you forgot that the Hatari debugger expects decimal unless you tell it otherwise. So you try again, typing it in as proper hexadecimal:

> d 13d18
Extra characters in decimal based number '13d18'!
Invalid address value '13d18'!
> d $13d18
START:
00013d18 123a fff8                move.b (pc,$fff8) == $00013d12 [08],d1
00013d1c d23a fff5                add.b (pc,$fff5) == $00013d13 [05],d1
00013d20 d23a fff2                add.b (pc,$fff2) == $00013d14 [02],d1
00013d24 d23a ffef                add.b (pc,$ffef) == $00013d15 [07],d1
00013d28 d23a ffec                add.b (pc,$ffec) == $00013d16 [04],d1
00013d2c 4e71                     nop 
DONE:
00013d2e 4e71                     nop 
00013d30 4267                     clr.w -(a7) [0000]
00013d32 4e41                     trap #$01
00013d34 0000 0000                or.b #$00,d0
00013d38 0000 0000                or.b #$00,d0
...
>

Twilight Zone ? (Cue creepy music.)

LoL. Optimization. It's using the PC relative modes because they take fewer bytes. We wanted to do that later, but we wanted to do that explicitly. Not yet. Not here.

This is one of the reasons I was hesitant to use vasm.

Sigh. Well, there are switches to turn optimizations off. Not really a problem.

I'd go ahead and step through the optimized code, but we want to do that in a few more minutes, with explicit code. So, for now, let's (q)uit out of the debugger and Hatari and try again:

$ vasmm68k_mot -Ftos -no-opt -o SUMCONST.PRG -L sumconst.lst sumconst.s

Here's the listing it produces with the no-opts switch:

Sections:
00: "text" (0-32)


Source: "sumconst.s"
                            	     1: 	OPT LIST,SYMTAB	; Options we want for the stand-alone assembler.
                            	     2: 	MACHINE MC68000	; because there are a lot the assembler can do.
                            	     3: 	OPT DEBUG	; We want the debugger to know our labels.
                            	     4: 	OUTPUT
                            	     5: ***********************************************************************
                            	     6: *	EVEN		; byte data doesn't have to be aligned.
00:00000000 4EF90000000C    	     7: ENTRY	JMP	START
                            	     8: *
00:00000006 08              	     9: BYTE8	DC.B	8
00:00000007 05              	    10: BYTE5	DC.B	5
00:00000008 02              	    11: BYTE2	DC.B	2
00:00000009 07              	    12: BYTE7	DC.B	7
00:0000000A 04              	    13: BYTE4	DC.B	4
                            	    14: *
                            	    15: 	EVEN		; But 68K code does have to be even aligned.
00:0000000C 123900000006    	    16: START	MOVE.B	BYTE8,D1
00:00000012 D23900000007    	    17: 	ADD.B	BYTE5,D1
00:00000018 D23900000008    	    18: 	ADD.B	BYTE2,D1
00:0000001E D23900000009    	    19: 	ADD.B	BYTE7,D1
00:00000024 D2390000000A    	    20: 	ADD.B	BYTE4,D1
00:0000002A 4E71            	    21: 	NOP
00:0000002C 4E71            	    22: DONE	NOP
                            	    23: * One way to return to the OS or other calling program
00:0000002E 4267            	    24: 	clr.w	-(sp)	; there should be enough room on the caller's stack
00:00000030 4E41            	    25: 	trap	#1			quick exit
                            	    26: 
                            	    27: 
                            	    28: 


Symbols by name:
BYTE2                           00:00000008
BYTE4                           00:0000000A
BYTE5                           00:00000007
BYTE7                           00:00000009
BYTE8                           00:00000006
DONE                            00:0000002C
ENTRY                           00:00000000
START                           00:0000000C

Symbols by value:
00000000 ENTRY
00000006 BYTE8
00000007 BYTE5
00000008 BYTE2
00000009 BYTE7
0000000A BYTE4
0000000C START
0000002C DONE  

That looks much better. Let's get it into the debugger. 

Again, 

  1. Start Hatari.
  2. When the GUI comes up, use Ctrl-Z to break out of GEM into the TOS command line shell.
  3. Change to the primer directory:
    C:\>CD PRIMER
    C:\primer>
  4. Use Alt-PAUSE to break out of TOS shell into the debugger.
  5. Set a PC breakpoint at the beginning of the TEXT segment:
    >b pc = TEXT :once
  6. (c)ontinue back to TOS shell.
  7. Invoke the executable created by the assembler:
    C:\primer>SUMCONST.PRG

Then we can

  • (d)isassemble the code (from START this time)
  • (m)emory dump (notice I'm using the count argument this time)
  • and alternate
    • (r)egister dump
    • (s)tep
  • until we hit the landing pad

as follows:

    ----------------------------------------------------------------------
    You have entered debug mode. Type c to continue emulation, h for help.
    
    CPU=$e1d7e2, VBL=1385, FrameCycles=128, HBL=0, LineCycles=128, DSP=N/A
    00e1d7e2 46c0                     move.w d0,sr
    > b pc = TEXT :once
    CPU condition breakpoint 1 with 1 condition(s) added:
    	pc = TEXT
    -> Break only once, and delete breakpoint afterwards.
    > c
    Returning to emulation...
    1. CPU breakpoint condition(s) matched 1 times.
    	pc = TEXT :once
    Removed CPU breakpoint 1:
    	pc = TEXT :once
    Reading symbols from program '/home/nova/usr/share/hatari/C:/primer/SUMCONST.PRG' symbol table...
    TOS executable, DRI / GST symbol table, reloc=0, program flags: PRIVATE (0x0)
    Program section sizes:
      text: 0x32, data: 0x0, bss: 0x0, symtab: 0x70
    Trying to load DRI symbol table at offset 0x4e...
    Offsetting BSS/DATA symbols from TEXT section.
    Skipping duplicate address & symbol name checks when autoload is enabled.
    Loaded 8 symbols (8 TEXT) from '/home/nova/usr/share/hatari/C:/primer/SUMCONST.PRG'.
    
    CPU=$13d10, VBL=2479, FrameCycles=63376, HBL=62, LineCycles=384, DSP=N/A
    00013d10 4ef9 0001 3d1c           jmp $00013d1c
    > d $13d1c
    START:
    00013d1c 1239 0001 3d16           move.b $00013d16 [08],d1
    00013d22 d239 0001 3d17           add.b $00013d17 [05],d1
    00013d28 d239 0001 3d18           add.b $00013d18 [02],d1
    00013d2e d239 0001 3d19           add.b $00013d19 [07],d1
    00013d34 d239 0001 3d1a           add.b $00013d1a [04],d1
    00013d3a 4e71                     nop 
    DONE:
    00013d3c 4e71                     nop 
    00013d3e 4267                     clr.w -(a7) [0000]
    00013d40 4e41                     trap #$01
    00013d42 0000 0000                or.b #$00,d0
    00013d46 0000 0000                or.b #$00,d0
    ...
    > m $13d10 64
    00013D10: 4e f9 00 01 3d 1c 08 05 02 07 04 00 12 39 00 01   N...=........9..
    00013D20: 3d 16 d2 39 00 01 3d 17 d2 39 00 01 3d 18 d2 39   =..9..=..9..=..9
    00013D30: 00 01 3d 19 d2 39 00 01 3d 1a 4e 71 4e 71 42 67   ..=..9..=.NqNqBg
    00013D40: 4e 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00   NA..............
    > r               
      D0 00000000   D1 00000000   D2 00000000   D3 00000000 
      D4 00000000   D5 00000000   D6 00000000   D7 00000000 
      A0 00000000   A1 00000000   A2 00000000   A3 00000000 
      A4 00013D42   A5 00013D42   A6 00077FC6   A7 00077FF8 
    USP  00077FF8 ISP  00007E64 
    T=00 S=0 M=0 X=0 N=0 Z=0 V=0 C=0 IMASK=3 STP=0
    Prefetch 4ef9 (JMP) 0001 (OR) Chip latch 00000000
    00013d10 4ef9 0001 3d1c           jmp $00013d1c
    Next PC: 00013d16
    > s
    
    CPU=$13d1c, VBL=2479, FrameCycles=63388, HBL=62, LineCycles=396, DSP=N/A
    00013d1c 1239 0001 3d16           move.b $00013d16 [08],d1
    > r
      D0 00000000   D1 00000000   D2 00000000   D3 00000000 
      D4 00000000   D5 00000000   D6 00000000   D7 00000000 
      A0 00000000   A1 00000000   A2 00000000   A3 00000000 
      A4 00013D42   A5 00013D42   A6 00077FC6   A7 00077FF8 
    USP  00077FF8 ISP  00007E64 
    T=00 S=0 M=0 X=0 N=0 Z=0 V=0 C=0 IMASK=3 STP=0
    Prefetch 1239 (MOVE) 0001 (OR) Chip latch 00000000
    00013d1c 1239 0001 3d16           move.b $00013d16 [08],d1
    Next PC: 00013d22
    > s
    
    CPU=$13d22, VBL=2479, FrameCycles=63404, HBL=62, LineCycles=412, DSP=N/A
    00013d22 d239 0001 3d17           add.b $00013d17 [05],d1
    > r
      D0 00000000   D1 00000008   D2 00000000   D3 00000000 
      D4 00000000   D5 00000000   D6 00000000   D7 00000000 
      A0 00000000   A1 00000000   A2 00000000   A3 00000000 
      A4 00013D42   A5 00013D42   A6 00077FC6   A7 00077FF8 
    USP  00077FF8 ISP  00007E64 
    T=00 S=0 M=0 X=0 N=0 Z=0 V=0 C=0 IMASK=3 STP=0
    Prefetch d239 (ADD) 0001 (OR) Chip latch 00000000
    00013d22 d239 0001 3d17           add.b $00013d17 [05],d1
    Next PC: 00013d28
    > s
    
    CPU=$13d28, VBL=2479, FrameCycles=63420, HBL=62, LineCycles=428, DSP=N/A
    00013d28 d239 0001 3d18           add.b $00013d18 [02],d1
    > r
      D0 00000000   D1 0000000D   D2 00000000   D3 00000000 
      D4 00000000   D5 00000000   D6 00000000   D7 00000000 
      A0 00000000   A1 00000000   A2 00000000   A3 00000000 
      A4 00013D42   A5 00013D42   A6 00077FC6   A7 00077FF8 
    USP  00077FF8 ISP  00007E64 
    T=00 S=0 M=0 X=0 N=0 Z=0 V=0 C=0 IMASK=3 STP=0
    Prefetch d239 (ADD) 0001 (OR) Chip latch 00000000
    00013d28 d239 0001 3d18           add.b $00013d18 [02],d1
    Next PC: 00013d2e
    > s
    
    CPU=$13d2e, VBL=2479, FrameCycles=63436, HBL=62, LineCycles=444, DSP=N/A
    00013d2e d239 0001 3d19           add.b $00013d19 [07],d1
    > r
      D0 00000000   D1 0000000F   D2 00000000   D3 00000000 
      D4 00000000   D5 00000000   D6 00000000   D7 00000000 
      A0 00000000   A1 00000000   A2 00000000   A3 00000000 
      A4 00013D42   A5 00013D42   A6 00077FC6   A7 00077FF8 
    USP  00077FF8 ISP  00007E64 
    T=00 S=0 M=0 X=0 N=0 Z=0 V=0 C=0 IMASK=3 STP=0
    Prefetch d239 (ADD) 0001 (OR) Chip latch 00000000
    00013d2e d239 0001 3d19           add.b $00013d19 [07],d1
    Next PC: 00013d34
    > s
    
    CPU=$13d34, VBL=2479, FrameCycles=63452, HBL=62, LineCycles=460, DSP=N/A
    00013d34 d239 0001 3d1a           add.b $00013d1a [04],d1
    > r
      D0 00000000   D1 00000016   D2 00000000   D3 00000000 
      D4 00000000   D5 00000000   D6 00000000   D7 00000000 
      A0 00000000   A1 00000000   A2 00000000   A3 00000000 
      A4 00013D42   A5 00013D42   A6 00077FC6   A7 00077FF8 
    USP  00077FF8 ISP  00007E64 
    T=00 S=0 M=0 X=0 N=0 Z=0 V=0 C=0 IMASK=3 STP=0
    Prefetch d239 (ADD) 0001 (OR) Chip latch 00000000
    00013d34 d239 0001 3d1a           add.b $00013d1a [04],d1
    Next PC: 00013d3a
    > s
    
    CPU=$13d3a, VBL=2479, FrameCycles=63468, HBL=62, LineCycles=476, DSP=N/A
    00013d3a 4e71                     nop 
    

    At this point, we can either (q)uit the whole Hatari session, or, since I have added that extra code that allows us to return to what called us, (c) and go back to the TOS shell.

    Why did I put the sum in D1 this time instead of D0? Good question. If we make a really fine point of it, I could have kept the sum in D7, instead. LoL. We have lots of registers in the 68000, and which one might correspond to B is just a matter of convention -- although there is stack order, and, in the 68020, there are 64-bit results that are put in register pairs, so ...

    But let's look at what happens when we (explicitly this time) use PC relative addressing. Here's the code:

    	OPT LIST,SYMTAB	; Options we want for the stand-alone assembler.
    	MACHINE MC68000	; because there are a lot the assembler can do.
    	OPT DEBUG	; We want labels for debugging.
    	OUTPUT
    ***********************************************************************
    *	EVEN		; byte data doesn't have to be aligned.
    ENTRY	JMP	START
    *
    BYTE8	DC.B	8
    BYTE5	DC.B	5
    BYTE2	DC.B	2
    BYTE7	DC.B	7
    BYTE4	DC.B	4
    *
    	EVEN		; But 68K code does have to be even aligned.
    START	MOVE.B	BYTE8(PC),D1
    	ADD.B	BYTE5(PC),D1
    	ADD.B	BYTE2(PC),D1
    	ADD.B	BYTE7(PC),D1
    	ADD.B	BYTE4(PC),D1
    	NOP
    DONE	NOP
    * One way to return to the OS or other calling program
    	clr.w	-(sp)	; there should be enough room on the caller's stack
    	trap	#1			quick exit
    

    and the listing file:

    Sections:
    00: "text" (0-28)
    
    
    Source: "sumconpc.s"
                                	     1: 	OPT LIST,SYMTAB	; Options we want for the stand-alone assembler.
                                	     2: 	MACHINE MC68000	; because there are a lot the assembler can do.
                                	     3: 	OPT DEBUG	; We want labels for debugging.
                                	     4: 	OUTPUT
                                	     5: ***********************************************************************
                                	     6: *	EVEN		; byte data doesn't have to be aligned.
    00:00000000 4EF90000000C    	     7: ENTRY	JMP	START
                                	     8: *
    00:00000006 08              	     9: BYTE8	DC.B	8
    00:00000007 05              	    10: BYTE5	DC.B	5
    00:00000008 02              	    11: BYTE2	DC.B	2
    00:00000009 07              	    12: BYTE7	DC.B	7
    00:0000000A 04              	    13: BYTE4	DC.B	4
                                	    14: *
                                	    15: 	EVEN		; But 68K code does have to be even aligned.
    00:0000000C 123AFFF8        	    16: START	MOVE.B	BYTE8(PC),D1
    00:00000010 D23AFFF5        	    17: 	ADD.B	BYTE5(PC),D1
    00:00000014 D23AFFF2        	    18: 	ADD.B	BYTE2(PC),D1
    00:00000018 D23AFFEF        	    19: 	ADD.B	BYTE7(PC),D1
    00:0000001C D23AFFEC        	    20: 	ADD.B	BYTE4(PC),D1
    00:00000020 4E71            	    21: 	NOP
    00:00000022 4E71            	    22: DONE	NOP
                                	    23: * One way to return to the OS or other calling program
    00:00000024 4267            	    24: 	clr.w	-(sp)	; there should be enough room on the caller's stack
    00:00000026 4E41            	    25: 	trap	#1			quick exit
    

    And I'm going to let you step through it yourself instead of showing you what it looks like here. It's basically just a different way to get at the same data, like on the 6809, but with 32-bit addresses and 16-bit offsets to deal with. And we'll actually talk about that all later.

    This has been another really long one. As we say in Japan, 「ご苦労様。」 (Go-kurō-sama.) You've worked hard, even if you just read through and didn't take time to enjoy plugging the code in to watch it run.

    Wait a minute. If you just read through and didn't step or trace through the simulations, you've really missed out on all the fun. Go back. Watch the code execute. Play with things just a little to see if you can make anything interesting happen. 

    And now we can really say, “ご苦労様。”

    The next thing we need to do is take a small detour to make sure you have tools to deal with all the hexadecimal math that has your eyes glazing over.


    (Title Page/Index)

     

    No comments:

    Post a Comment