So, for whatever reason, I can’t use include files, which means I just have to have everything in one large assembly file. I guess that’s not the end of the world.
Lets start by trying to set up the timer and output a simple message.
TIMER0 EQU 40H ;LOCATION OF THE FIRST TIMER
TWORD0 EQU 00010101B ;TIMER WORD (A STATIC VALUE FOR NOW)
TTCON0 EQU 01H ;TIMER CONSTANT (STATIC FOR NOW)
; LETS FIRST TRY TO SET UP THE TIMER WITH A SINGLE, HAND BUILT CONTROL WORD
LD A,TWORD0
LD C,TIMER0
OUT (C),A
LD A,TTCON0
OUT (C),A
Code language: PHP (php)
OK, that worked!
Next I’d like to try to build that word in code, using a number of variables. Up until now we’ve mostly been dealing with symbols, using the EQU pseudo-0p. I think if we want to define single byte storage areas, we can use DB, and give those locations a label.
To build up a control byte from a number of single bits, we have to shift each bit into it’s correct place, then OR it with the control byte we’re building. Right now, I’m thinking of this where each ‘bit’ is actually a byte that’s 1 or 0, and needs to be left shifted by the number of times as it’s position is in the byte.
Since we’re dealing with bytes that should only be a 0 or a 1, we don’t need to worry about shift vs rotate vs carry vs whatever makes a bit pop back onto the other end. So lets use…. RLCA – Rotate Left Circular Accumulator. This will put a bit into the carry flag, but won’t put the carry flag back into the byte.
So we have to:
1) load each byte into the Accumulator
2) perform some number of RLCAs
3) load the control word into another register
4) perform an OR with that register
5) put the result from the accumulator back into that other register
6) load the next byte into the Accumulator and keep going
So I tried this little snip of code
;LETS TRY TO BUILD A CONTROL WORD WITH LEFT SHIFTS
LD A,TB7IN
RLCA
RLCA
RLCA
RLCA
RLCA
LD B,TWRD0
OR B
LD B,A
; LETS OUTPUT THIS ONTO THE CONSOLE. IT SHOULD BE AN @ CHARACTER, SINCE
; WE SHIFTED 1 OVER 5 TIMES TO THE 64'S BIT.
Code language: PHP (php)
With these DB entries below
;VARIABLE STORAGE ;TIMER CONTROL WORD BITS (EVEN THOGH THESE ARE REALLY BYTES.. THIS IS DUMB BUT WHATEVES) TB0CV DB 1 ;CONTOL WORD OR VECTOR ADDRESS - 1 BYTE IS CTRL WRD TB1RS DB 0 ;RESET TB2TC DB 1 ;IS NEXT BYTE TIME CONSTANT TB3TT DB 0 ;TIMER TRIGGER - 0 STARTS RIGHT AWAY TB4ES DB 1 ;EDGE SELECTION - 1 RISING TB5PS DB 0 ;PRESCALER - 0 = 16, 1 = 256 TB6MD DB 0 ;MODE - 0 = TIMER, 1 = COUNTER TB7IN DB 1 ;INTERRUPT - 0 DISABLES, 1 ENABLES TWRD0 DB 00 ;THE WHOLE WORD
And I get errors on both lines that reference those memory locations:
DAY142.Z80 – Byte Out of Range Line 00039
LD A,TB7IN
DAY142.Z80 – Byte Out of Range Line 00045
LD B,TWRD0
Lets find out why: It’s been really useful to run the compiler with the /F option, which forces the creation of a listing. That way, we can see what opcodes were used, and see where the difference between what we thought should happen, and reality.
DAY142.Z80 - Byte Out of Range Line 00039
LD A,TB7IN
39 011E 3E 5A LD A,TB7IN
40 0120 07 RLCA
41 0121 07 RLCA
42 0122 07 RLCA
43 0123 07 RLCA
44 0124 07 RLCA
DAY142.Z80 - Byte Out of Range Line 00045
LD B,TWRD0
45 0125 06 5B LD B,TWRD0
Code language: CSS (css)
So the LD opcodes were 5A & 06, For LD A, I think I wanted opcode 3A, which expects a 16 bit address. Did I need to put the name of the variable in parentheses ? I assumed it would have figured that out for me. OK! Using parentheses for the first entry worked, and it chose the right opcode. It didn’t chose the right opcode for B, because there isn’t one.
Not all registers are created equal. The A register can be loaded from any 16 bit address in memory, while the other registers have more limited instructions. If we want to load the B register from memory, we must first place that address in the HL register. So lets try that.
OK! Well that compiled without error, but I don’t know if it worked – More tomorrow.
What I’m still not 100% sure on is when to use parentheses with memory location labels, and when not to. I should really investigate the various flavors of LD tomorrow.
Also, in retrospect, I don’t think we actually need separate areas in memory to hold the individual bits. I think we’re better off just writing routines that can set or clear each bit in the control word.
And… Looking at the list file, we can see that LD A,(LOCATION) loads the contents of LOCATION into A, while LD HL,LOCATION loads the address of LOCATIOn into HL.
39 011E 3A 015D LD A,(TB7IN) 45 0126 21 015E LD HL,TWRD0 96 015D 01 TB7IN DB 1 ;INTERRUPT - 0 DISABLES, 1 ENABLES 97 015E 00 TWRD0 DB 00 ;THE WHOLE WORD