introduction_to_programming_the_beamracer
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
introduction_to_programming_the_beamracer [2020/05/25 15:53] – laubzega | introduction_to_programming_the_beamracer [2020/10/08 14:45] – [Local Memory] laubzega | ||
---|---|---|---|
Line 2: | Line 2: | ||
==== Overview ==== | ==== Overview ==== | ||
- | Producing non-trivial | + | Producing non-trivial |
The downside of this is quite obvious - 6510 spends at least some time doing nothing but waiting for the right moment(s) to nudge the VIC-II. This can be partially mitigated with the help of interrupts, but high precision required by many advanced effects means that the CPU is otherwise unavailable for a significant portion of the video frame. | The downside of this is quite obvious - 6510 spends at least some time doing nothing but waiting for the right moment(s) to nudge the VIC-II. This can be partially mitigated with the help of interrupts, but high precision required by many advanced effects means that the CPU is otherwise unavailable for a significant portion of the video frame. | ||
Line 13: | Line 13: | ||
==== What is VASYL === | ==== What is VASYL === | ||
- | VASYL is the core logic chip on the BeamRacer board, incarnated inside Altera MAX-II EPM1270 | + | VASYL is the core logic chip on the BeamRacer board, incarnated inside Altera MAX-II EPM1270. Working in synchrony with VIC-II, it controls various auxiliary chips and executes software programs (so-called display lists) that define what’s going to happen at particular times in a video frame. VASYL fetches display list instructions from a local memory at a maximum rate of one per system clock cycle. Some of these instructions only affect VASYL’s internal state, some have an impact on VIC-II or 6510. With careful programming, |
{{: | {{: | ||
Line 20: | Line 20: | ||
==== Initialization ==== | ==== Initialization ==== | ||
- | In order to maintain a high level of compatibility with existing C64 software, BeamRacer remains hidden on power on, and the computer behaves as if it was not there. That is, register writes are ignored, and reads report the same values as those in a vanilla C64. | + | In order to maintain a high level of compatibility with existing C64 software, BeamRacer remains hidden on power up, and the computer behaves as if it was not there. That is, register writes are ignored, and reads report the same values as those in a vanilla C64. |
- | It is necessary to perform so-called “register knocking” for the board to reveal its presence. This is achieved by writing a sequence $42, $52 (screen codes for “BR”) to register $D030. To check if the board is indeed there, register $D030 can be then read and compared with “0”. | + | It is necessary to perform so-called “register knocking” for the board to reveal its presence. This is achieved by writing a sequence $42, $52 (screen codes for “BR”) to register $D031. To check if the board is indeed there, register $D031 can then be read and compared with “0”. |
< | < | ||
- | LDX $D030 | + | VREG_CONTROL = $D031 |
+ | |||
+ | LDX VREG_CONTROL | ||
INX | INX | ||
BNE BEAMRACER_ALREADY_ACTIVE | BNE BEAMRACER_ALREADY_ACTIVE | ||
LDX #$42 | LDX #$42 | ||
- | STX $D030 | + | STX VREG_CONTROL |
LDX #$52 | LDX #$52 | ||
- | STX $D030 | + | STX VREG_CONTROL |
- | LDX $D030 | + | LDX VREG_CONTROL |
BEQ BEAMRACER_FOUND_AND_ACTIVATED | BEQ BEAMRACER_FOUND_AND_ACTIVATED | ||
RTS ; sadly, no BeamRacer... | RTS ; sadly, no BeamRacer... | ||
Line 39: | Line 41: | ||
==== Local Memory ==== | ==== Local Memory ==== | ||
- | For VASYL to execute a display list, it first needs to be placed in its local memory (LRAM). BeamRacer provides VASYL with 512KiB of LRAM, organized in 8 banks of 64KiB each. The 6510 can put data into LRAM using two one-byte wide ports. Each port is built out of five registers: | + | For VASYL to execute a display list, it first needs to be placed in its local memory (LRAM). BeamRacer provides VASYL with eight banks of 64KiB of LRAM each. The 6510 can put data into LRAM using two one-byte wide ports. Each port is built out of five registers: |
* [[registers# | * [[registers# | ||
Line 47: | Line 49: | ||
* [[registers# | * [[registers# | ||
- | ADRL/ADRH are respectively the LSB and MSB of a 16-bit address in a LRAM memory bank. Together they determine the location where data will be written to (or read from), while register PORT is used to transfer the actual value. A following code | + | ADRL/ADRH are respectively the LO and HI bytes of a 16-bit address in a LRAM memory bank. Together they determine the location where data will be written to (or read from), while register PORT is used to transfer the actual value. A following code |
< | < | ||
Line 65: | Line 67: | ||
LDA #$20 | LDA #$20 | ||
STA VREG_ADR0H | STA VREG_ADR0H | ||
- | LDA #$01 ; advance LRAM pointer by one on every transfer | + | LDA #$01 ; advance LRAM pointer by one after every transfer |
STA VREG_STEP0 | STA VREG_STEP0 | ||
LDX #0 | LDX #0 | ||
Line 75: | Line 77: | ||
</ | </ | ||
- | On some occasions you may also want to read from LRAM with the CPU. There is an extra step involved, as many 6510 addressing modes result in a bus READ access before the requested WRITE occurs, which could lead to confusing results if not used with care. Register | + | On some occasions you may also want to read from LRAM with the CPU. There is an extra step involved, as many 6510 addressing modes result in a bus READ access before the requested WRITE occurs, which could lead to confusing results if not used with care. Register |
< | < | ||
- | LDA VREG_CTRL1 | + | LDA VREG_CONTROL |
ORA # | ORA # | ||
- | STA VREG_CTRL1 | + | STA VREG_CONTROL |
LDA #$00 | LDA #$00 | ||
Line 131: | Line 133: | ||
the second instruction will be ignored and act as a NOP (no-operation). | the second instruction will be ignored and act as a NOP (no-operation). | ||
- | [[registers# | + | [[registers# |
<code vasyl> | <code vasyl> | ||
Line 142: | Line 144: | ||
<code vasyl> | <code vasyl> | ||
- | dlist: | ||
WAIT 48,13 | WAIT 48,13 | ||
MOV $20, 1 | MOV $20, 1 | ||
Line 149: | Line 150: | ||
MOV $20, 0 | MOV $20, 0 | ||
END ; this is a handy alias for instruction "WAIT 511, | END ; this is a handy alias for instruction "WAIT 511, | ||
- | dlend: | ||
</ | </ | ||
Line 161: | Line 161: | ||
<code vasyl> | <code vasyl> | ||
- | dlist: | ||
WAIT 48, 0 | WAIT 48, 0 | ||
MOV $20,15 | MOV $20,15 | ||
Line 169: | Line 168: | ||
MOV $20,15 | MOV $20,15 | ||
END | END | ||
- | dlend: | ||
</ | </ | ||
Line 176: | Line 174: | ||
<code vasyl> | <code vasyl> | ||
- | dlist: | ||
WAIT 48, 0 ; starting line | WAIT 48, 0 ; starting line | ||
MOV | MOV | ||
Line 184: | Line 181: | ||
MOV | MOV | ||
END | END | ||
- | dlend: | ||
</ | </ | ||
Line 210: | Line 206: | ||
<code vasyl> | <code vasyl> | ||
- | dlist: | ||
WAIT 48, 0 ; starting line | WAIT 48, 0 ; starting line | ||
loop: | loop: | ||
Line 223: | Line 218: | ||
BRA loop ; loop endlessly | BRA loop ; loop endlessly | ||
END ; never reached | END ; never reached | ||
- | dlend: | ||
</ | </ | ||
Line 230: | Line 224: | ||
{{: | {{: | ||
- | Note that although our exercise resulted in an infinite loop (BRA is __always__ jumping back), no crash or hang occurs - the computer operates perfectly fine and not a bit slower. This is because at the end of every frame the execution of display list is aborted, and then immediately restarted | + | Note that although our exercise resulted in an infinite loop (BRA is __always__ jumping back), no crash or hang occurs - the computer operates perfectly fine and not a bit slower. This is because at the end of every frame the execution of display list is aborted, and then immediately restarted |
While this nice feature of VASYL makes infinite loops practical, in many situations we want to have more control over the number of loop repetitions. Let's close this intro chapter with two more instructions useful for exactly that. | While this nice feature of VASYL makes infinite loops practical, in many situations we want to have more control over the number of loop repetitions. Let's close this intro chapter with two more instructions useful for exactly that. | ||
- | === CSET and CDEC === | + | === SET and DEC === |
- | VASYL contains two internal 8-bit counters | + | VASYL contains two internal 8-bit counters |
- | Instruction " | + | Instruction " |
<code vasyl> | <code vasyl> | ||
- | | + | |
- | | + | |
</ | </ | ||
- | To make a counter run, we now need to use instruction " | + | To make a counter run, we now need to use instruction " |
- | <code vasyl [highlight_lines_extra=" | + | <code vasyl [highlight_lines_extra=" |
- | dlist: | + | |
WAIT 48, 0 ; starting line | WAIT 48, 0 ; starting line | ||
- | | + | |
loop: | loop: | ||
MOV $20, 8 | MOV $20, 8 | ||
Line 260: | Line 253: | ||
MOV $20, 0 | MOV $20, 0 | ||
DELAYV | DELAYV | ||
- | | + | |
BRA loop ; will be skipped when counter 0 reaches 0 | BRA loop ; will be skipped when counter 0 reaches 0 | ||
END | END | ||
- | dlend: | ||
</ | </ | ||
Line 270: | Line 262: | ||
{{: | {{: | ||
- | What happened here? On the first iteration through the loop, the counter holds value 3. This is clearly different from 0, so all CDEC does is to decrement it by one. On the next iteration (when the second rasterbar is drawn) it holds value 2. On the third (third rasterbar) - the value is 1. Finally, on the fourth iteration (fourth rasterbar), the counter holds the value of 0. When we get to execute | + | What happened here? On the first iteration through the loop, the counter |
A good thing about having two counters is that they can be used to construct nested loops. How about drawing three groups of four rasterbars each, where space between groups is twice the size of space between individual bars? Please give it a try! | A good thing about having two counters is that they can be used to construct nested loops. How about drawing three groups of four rasterbars each, where space between groups is twice the size of space between individual bars? Please give it a try! | ||
- | Finally, be aware that when CDEC decides to skip, it has no idea how many bytes the next instruction | + | Finally, be aware that when DECA or DECB decides to skip, it has no idea how many bytes the next instruction |
This concludes our introduction to BeamRacer programming. Please practice what you have learned here before moving on to the next chapter. | This concludes our introduction to BeamRacer programming. Please practice what you have learned here before moving on to the next chapter. | ||
introduction_to_programming_the_beamracer.txt · Last modified: 2021/09/10 01:49 by silverdr