Hello, World!
(Not Yet on the Beach)
6801 (EXORsim6801)
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.
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.
No comments:
Post a Comment