introduction_to_programming_the_beamracer
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
introduction_to_programming_the_beamracer [2020/05/25 14:46] – [Local Memory] laubzega | introduction_to_programming_the_beamracer [2021/09/10 01:49] (current) – [Initialization] silverdr | ||
---|---|---|---|
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 verified. Value of $FF means that BeamRacer was NOT activated.((Please note that early revisions of this chapter, and the code snippet below, advocated checking for $00 as an indicator that the BeamRacer was activated. This is now deprecated and may lead to "false negative" |
< | < | ||
- | 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 | + | INX |
+ | BNE BEAMRACER_FOUND_AND_ACTIVATED | ||
RTS ; sadly, no BeamRacer... | RTS ; sadly, no BeamRacer... | ||
</ | </ | ||
Line 39: | Line 42: | ||
==== 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 50: | ||
* [[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 68: | ||
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 78: | ||
</ | </ | ||
- | 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 134: | ||
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 145: | ||
<code vasyl> | <code vasyl> | ||
- | dlist: | ||
WAIT 48,13 | WAIT 48,13 | ||
MOV $20, 1 | MOV $20, 1 | ||
Line 149: | Line 151: | ||
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 162: | ||
<code vasyl> | <code vasyl> | ||
- | dlist: | ||
WAIT 48, 0 | WAIT 48, 0 | ||
MOV $20,15 | MOV $20,15 | ||
Line 169: | Line 169: | ||
MOV $20,15 | MOV $20,15 | ||
END | END | ||
- | dlend: | ||
</ | </ | ||
Line 176: | Line 175: | ||
<code vasyl> | <code vasyl> | ||
- | dlist: | ||
WAIT 48, 0 ; starting line | WAIT 48, 0 ; starting line | ||
MOV | MOV | ||
Line 184: | Line 182: | ||
MOV | MOV | ||
END | END | ||
- | dlend: | ||
</ | </ | ||
Line 210: | Line 207: | ||
<code vasyl> | <code vasyl> | ||
- | dlist: | ||
WAIT 48, 0 ; starting line | WAIT 48, 0 ; starting line | ||
loop: | loop: | ||
Line 223: | Line 219: | ||
BRA loop ; loop endlessly | BRA loop ; loop endlessly | ||
END ; never reached | END ; never reached | ||
- | dlend: | ||
</ | </ | ||
Line 230: | Line 225: | ||
{{: | {{: | ||
- | 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 254: | ||
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 263: | ||
{{: | {{: | ||
- | What happened here? On the first iteration through the loop, the counter holds value 3. This is clearly different | + | 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.1590443169.txt.gz · Last modified: 2020/05/25 14:46 by laubzega