Saturday, August 24, 2024

ALPP 01-12 -- Hello, World! (Not Yet on the Beach) -- 6801 (EXORsim6801)

Hello, World!
(Not Yet on the Beach)
6801 (EXORsim6801)

(Title Page/Index)

 

So I didn't actually check whether there would be any special problems with running the 6800 code in the 6801 simulator in the Hello World exercise using the EXbug monitor ROM routines before telling you the code would be exactly the same except for timing. Didn't check until I started testing the code on the foothold chapter for the 6801.

My bad. Sorry about that.

The code and how it runs is exactly the same except for instruction cycle counts (time), but the EXORsim6801 simulator is from an earlier version of EXORsim, and it does some stuff that needs explaining. And it needs a workaround that requires timing and initialization loops, which are topics I wanted to avoid until I had laid a better foundation.

But timing loops, as much as they really shouldn't be used if you can avoid them, are basically the simplest deterministically terminating loops. And the terminal initialization loop is pretty straightforward, as well. So this can be viewed as a soft introduction to branching and loops.

Whether you work through the 68000 code in the Hello World exercise on the Atari ST first or not is probably not that important. Just don't skip either that chapter or this.

Anyway, here's why this chapter is necessary --

I made the fork of EXORsim when JHAllen was working on getting the terminal emulation to work better, and I just grabbed it at a bad point in the code, I think. Anyway, this version needs about a screenfull of carriage return/line feed combination to start putting text on the screen. And it also always shows a traceback when it hits a breakpoint, which makes it hard to see what happened, especially if the terminal you're using doesn't have a scrollback (history) buffer.

The former leaves you unable to see output until there is a lot. So we need to make more than a single character.

The latter means you have to scroll back up in your scroll (history) buffer, if you've enabled it. If you haven't enabled it, do so now. If your terminal emulator doesn't have such a thing, install one that does. 

If your workstation is a Linux OS workstation, XTerm or something similar should be available. Look for the scroll-back setting and set it for at least a couple of thousand lines, and you should be good. 

If you're working on Cygwin under MSWindows, I think you can install XTerm or something similar. If you're working straight under MSWindows, I think the power shell should do this for you, even if the command-line shell for the OS version you're using doesn't. 

For the problem of having to wade through the traceback, I suggest a timing loop. The emulation seems to be running fast, so the usual million cycles equals one second at 1 MHz clock calculation doesn't work out.

For the former problem, I suggest simply putting a new line character combination in front of the character and after, and putting the character and trailing new line combo in a loop, enough times to fill the screen with new lines. 

Here's a simple delay loop using the B accumulator:

SOFTMR	LDAB	#100	; 500 microseconds at 1 MHz clock.
SOFTLP	DECB		; 2~
	BNE	SOFTLP	; 3~ : tot. 5~
	...

I think it's fairly self-explanatory with the comments. But I'll be long-winded --

DECB, as you might guess, means decrement the B accumulator -- subtract 1 from it.

BNE means branch if not equal. Branches are like jumps, but shorter. (There is more to be said about that, but it'll do for now.) 

Branch if not equal to what? In this case, not equal to zero. (In all cases ≠ 0, really, but more on that later.)

So the code keeps subtracting 1 from the contents of B and branching back to do it again until B hits 0. If you start from a hundred, that's going to take a hundred times to count out. 

If the processor were a human, it would be complaining. But it's just doing what it was designed to do, so apparently it doesn't complain.

DECB takes 2 cycles, and BNE takes 3. That's a total of 5 cycles each time through.

5 times 100 is 500. 

A 1 MHz clock has a period of 1 microsecond, so 500 clocks should be 500 μS. (LDAB immediate takes another 2 cycles, so it's actually a total of 502  μS.)

You can use the X register as well. DEX takes 3 cycles, so it would be 6 cycles per loop. 

Also, on the 6801 and 6809, you can use the double accumulator D, using SUBD subtract from D immediate, since there is no special decrement D instruction:

SOFTMR	LDD	#100	; 700 microseconds at 1 MHz clock.
SOFTLP	SUBD	#1	; 4~
	BNE	SOFTLP	; 3~ : tot. 7~
	...

You can nest loops to get longer times, and you can decrement a byte in memory, as well:

	ORG	$90
COUNT	RMB	1	; one byte counter
	...
	ORG	$2000
	...
SOFTMR	LDAB	#10	; a little bit more than a second
	STAB	COUNT
SOFLOUT	LDA	#100	; a little bit more than 100 milliseconds
SOFLMID	LDAB	#200	; a little bit more than 1000 μS at 1 MHz
SOFLIN	DECB		; 2~
	BNE	SOFLIN	; 3~ : tot. 5~
	DECA		; 2~ : tot. 1004 μS at 1 MHz
	BNE	SOFLMID	; 3~ : tot. 1007 μS at 1 MHz
	DEC	COUNT	; 6~ : tot. 100706 μS at 1 MHz
	BNE	SOFLOUT	; 3= : tot. 100709 μS at 1 MHz
	...

(The ORG directives change where the code is assembled. Ignore them for now; I'm putting them in here to show that the variables and code are in different places, and so you'll sort-of recognize them later. More explanation then.)

Of course, you can tune the initial counts to get closer to a true one-second total delay. But you really want to do this another way if you can.

Now, if you can branch back to do nothing but count, you can also branch back to output the same character over and over. And that's what we'll do to get enough output to get the terminal emulator code in this older version of EXORsim to respond: 

* Essential control codes
LF	EQU	$0A	; line feed
CR	EQU	$0D	; carriage return
*
XOUTCH	EQU	$F018
*
ENTRY	LDAA	#CR	; Put out a CR/LF to start.
	JSR	XOUTCH
	LDAA	#LF
	JSR	XOUTCH
*
* Now let's try putting an H on the screen.
* But let's put a bunch out, with end-of-line.
	LDAB	#40	; more than a screen full of lines
*
* Output the character,
CLOOP	LDAA	#'H	; the character to ouput
	JSR	XOUTCH	; Call the output routine in monitor ROM
*
* ... and the end of line.
	LDAA	#CR	; CR/LF to start
	JSR	XOUTCH
	LDAA	#LF
	JSR	XOUTCH
	DECB		; count down the number of lines
	BNE	CLOOP	; If not zero, go back and do it again.
*
* This is not the best timing LOOP for all purposes.
* Also, timing LOOPs are usually not the correct solution.
* Usually.
PAUSE	LDAA	#5	; adjust this for your workstation.
	CLRB
	LDX	#0
PLOOP	DEX		; 3~
* If not 0 after dec, go back and dec again
	BNE	PLOOP	; 3~, tot 6 : 65536 times => 393216~ 
	DECB		; 2~, tot 393218~
	BNE	PLOOP	; 3~, tot 393221~ : times 256 => 100664576~
* At 1 MHz, that should be about 100 seconds.
* But the emulator seems to be running a bit fast.
* It's about 2 seconds on my workstation.
	DECA		; 100664578~
	BNE	PLOOP	; 100664581~ : times 5 => 503322905
* Should be about 10 seconds on my workstation.
DONE	NOP	; landing pad
	NOP

Yeah, it's no longer short. 

Step through the initialization code for a bit, set a (b)reakpoint and (c)ontinue when you get bored, and scroll back when you hit the breakpoint. The timing loop should give you enough time to see the output before the traceback listing hits the screen.

We'll use the same strategy for the full string, printing the full string with the CR/LF at the end enough times to fill the screen with lines, then delaying hopefully long enough to get a look at the output without having to scroll back:

* Essential control codes
LF	EQU	$0A	; line feed
CR	EQU	$0D	; carriage return
EOT	EQU	$04	; $04 is decimal 4
*
NATWID	EQU	2	; 2 bytes in the CPU's natural integer
*
XOUTCH	EQU	$F018	; character output, one at a time
XPDAT1	EQU	$F027	; string output, terminated by EOT
*
ENTRY	JMP	START
* (EXORsim apparently doesn't want to calculate RMB arguments.)
*	RMB	16*NATWID-1
	RMB	31	; 16 levels of call minus any saved registers, max
STKBAS	RMB	1	; 6800 is post-dec (post-store-decrement) push
*
SAVES	RMB	2	; a place to keep S so we can be clean
*
* Don't want an extra CR/LF in the loop.
*HELLO	FCB	CR,LF	; Put message at beginning of line
HELLO	FCB	"SEKAI YO, YAI!"	; Whatever the user wants here.
	FCB	CR,LF,EOT	; Put the debugger's output on a new line.
*
START	STS	SAVES	; Save what the monitor gives us.
	LDS	#STKBAS	; Move to our own stack
*
	LDAA	#CR	; CR/LF to start
	JSR	XOUTCH
	LDAA	#LF
	JSR	XOUTCH
*
* Now let's try putting the string on the screen.
* But let's put a bunch out.
	LDAB	#40	; more than a screen full of lines
*
* Now, output the string
CLOOP	PSHB		; save count (not really necessary)
	LDX	#HELLO	; point to the string
	JSR	XPDAT1	; output it
*
* ... and the end of line CR/LF is in the string.
	PULB		; restore count
	DECB		; count down the number of lines
	BNE	CLOOP	; If not zero, go back and do it again.
*
* This is not the best timing LOOP for all purposes.
* Also, timing LOOPs are usually not the correct solution.
* Usually.
PAUSE	LDAA	#5	; adjust this for your workstation.
	CLRB
	LDX	#0
PLOOP	DEX		; 3~
* If not 0 after dec, go back and dec again
	BNE	PLOOP	; 3~, tot 6 : 65536 times => 393216~ 
	DECB		; 2~, tot 393218~
	BNE	PLOOP	; 3~, tot 393221~ : times 256 => 100664576~
* At 1 MHz, that should be about 100 seconds.
* But the emulator seems to be running a bit fast.
* It's about 3 seconds on my workstation.
	DECA		; 100664578~
	BNE	PLOOP	; 100664581~ : times 5 => 503322905
* Should be about 10 seconds on my workstation.
	NOP
	NOP
Remember, this chapter was necessary not because of differences between the 6801 and the 6800, but because I've been too lazy to redo my EXORsim6801 (probably with correct timings this time) on JHAllen's most recent version.

And it makes a good excuse for a soft introduction of branches and loops. 

While we're in the mood for debugging, let's take a detour through debugging on the 6800 and 6809.

Or, if you haven't gone through Hello World on the Atari ST (Hatari) in the previous chapter yet, I'd strongly encourage you to do so.

If you've done all that, it's time for getting a real foothold by doing the string output ourselves in a split stack discipline.

(Title Page/Index)

 

 

 

 

No comments:

Post a Comment