[{"data":1,"prerenderedAt":291},["ShallowReactive",2],{"learn:invaders:03-move-base":3},{"item":4,"marksAgainst":290},{"slug":5,"number":6,"title":7,"idea":8,"models":9,"body":11,"tryIt":248,"game":272,"cites":273,"program":289},"03-move-base",3,"Move the base with the arrow keys","reading the keyboard, RET Z, and keeping the base inside the screen",[6,10],1,[12,18,22,26,86,90,93,112,115,128,131,150,152,156,158,175,178,207,210,234,237,241,244],{"kind":13,"inlines":14},"p",[15],{"kind":16,"text":17},"text","Hold the left or right arrow and the base slides along the bottom row, a cell a turn; at the screen's edges it stops. The game loop's turn has its first piece of work: each turn it looks at the arrows, and if one is down, moves the base.",{"kind":19,"id":20,"text":21},"h2","what-changed","What changed",{"kind":13,"inlines":23},[24],{"kind":16,"text":25},"Chapter 2's program, with these changes:",{"kind":27,"items":28},"ul",[29,35,49,62,72],[30,33],{"kind":31,"text":32},"strong","~",{"kind":16,"text":34}," The comment at the top, lines 1 to 5, now describes chapter 3.",[36,38,40,43,45,47],{"kind":31,"text":37},"+",{"kind":16,"text":39}," ",{"kind":41,"text":42},"code","MOVEBASE",{"kind":16,"text":44},", a new routine with its comment, below ",{"kind":41,"text":46},"DRAWBASE",{"kind":16,"text":48},": it reads the arrows and moves the base.",[50,51,53,56,58,60],{"kind":31,"text":32},{"kind":16,"text":52}," The game loop's comment: its last line now ends ",{"kind":54,"text":55},"em","this one moves the base",{"kind":16,"text":57}," in place of ",{"kind":54,"text":59},"this one only waits",{"kind":16,"text":61},".",[63,64,65,67,69,71],{"kind":31,"text":37},{"kind":16,"text":39},{"kind":41,"text":66},"CALL MOVEBASE",{"kind":16,"text":68}," in the loop, after ",{"kind":41,"text":70},"CALL WAIT",{"kind":16,"text":61},[73,74,75,77,79,81,83,84],{"kind":31,"text":37},{"kind":16,"text":39},{"kind":41,"text":76},"BLANK",{"kind":16,"text":78},", three spaces, after ",{"kind":41,"text":80},"BASE",{"kind":16,"text":82},": what ",{"kind":41,"text":42},{"kind":16,"text":85}," draws to erase the base.",{"kind":13,"inlines":87},[88],{"kind":16,"text":89},"Nothing is taken out.",{"kind":19,"id":91,"text":92},"the-keyboard-is-memory-too","The keyboard is memory too",{"kind":13,"inlines":94},[95,97,99,101,103,105,107,109,110],{"kind":16,"text":96},"The keyboard is read as memory, from ",{"kind":41,"text":98},"3800H",{"kind":16,"text":100},": its keys are wired in rows, and each row is read at its own address, ",{"kind":41,"text":102},"3801H",{"kind":16,"text":104}," to ",{"kind":41,"text":106},"3840H",{"kind":16,"text":108},". A key that is down reads as a 1 bit in its row's byte, a key that is up as a 0. The row read at ",{"kind":41,"text":106},{"kind":16,"text":111}," holds ENTER, CLEAR, BREAK, the four arrows and the space bar, and the left and right arrows are its bits 5 and 6: that order within the row is the one Fugløy's emulator uses, from the ROM's own keyboard routine, not a page of the manuals.",{"kind":41,"lang":113,"text":114},"z80","MOVEBASE:\n        LD      A,(3840H)       ; the arrows' row: bit 5 left, 6 right\n        AND     60H             ; keep those two bits (0110 0000)\n        RET     Z               ; neither is down: nothing to do\n        LD      C,A             ; keep the keys in C, so A is free",{"kind":13,"inlines":116},[117,119,121,123,125,126],{"kind":41,"text":118},"AND 60H",{"kind":16,"text":120}," keeps bits 5 and 6 and clears the rest, and sets the zero flag when what is left is 0, when neither arrow is down. ",{"kind":41,"text":122},"RET Z",{"kind":16,"text":124}," returns only when the zero flag is set; otherwise the routine runs on. So on most turns, with no key down, ",{"kind":41,"text":42},{"kind":16,"text":127}," is three instructions and back. If you did lesson 3, this is its read of the arrows.",{"kind":19,"id":129,"text":130},"erase-move-draw","Erase, move, draw",{"kind":13,"inlines":132},[133,135,136,138,140,142,143,145,146,148,149],{"kind":16,"text":134},"Nothing on the screen moves by itself. To move the base, ",{"kind":41,"text":42},{"kind":16,"text":137}," draws three spaces where it is, changes ",{"kind":41,"text":139},"BASEX",{"kind":16,"text":141},", and draws the base again at the new column. Chapter 2's ",{"kind":41,"text":46},{"kind":16,"text":144}," does both draws: HL says what to draw, ",{"kind":41,"text":76},{"kind":16,"text":147}," or ",{"kind":41,"text":80},{"kind":16,"text":61},{"kind":41,"lang":113,"text":151},"BLANK:  DB      '   '           ; three spaces, to erase it",{"kind":13,"inlines":153},[154],{"kind":16,"text":155},"Between the two draws the column changes by one:",{"kind":41,"lang":113,"text":157},"        LD      A,(BASEX)       ; the base's column, from memory\n        BIT     5,C             ; left?\n        JR      Z,NOTLT\n        CP      0               ; column 0, the left edge: stay\n        JR      Z,NOTLT\n        DEC     A\nNOTLT:\n        BIT     6,C             ; right?\n        JR      Z,NOTRT\n        CP      61              ; column 61, the right edge for three cells: stay\n        JR      Z,NOTRT\n        INC     A\nNOTRT:\n        LD      (BASEX),A       ; the new column, back to memory",{"kind":13,"inlines":159},[160,162,164,166,168,170,172,174],{"kind":41,"text":161},"BIT 5,C",{"kind":16,"text":163}," sets the zero flag when bit 5 of C is 0, so ",{"kind":41,"text":165},"JR Z,NOTLT",{"kind":16,"text":167}," skips the move left when the left arrow is up. ",{"kind":41,"text":169},"CP 0",{"kind":16,"text":171}," compares A with 0: it sets the flags as A minus 0 would, zero when A is 0, and leaves A as it was. At column 0 the base is at the left edge and stays; at 61 its right wing is in column 63, the last, and it stays. That is the whole of ",{"kind":54,"text":173},"kept inside the screen",{"kind":16,"text":61},{"kind":19,"id":176,"text":177},"why-drawbase-keeps-bc","Why DRAWBASE keeps BC",{"kind":13,"inlines":179},[180,181,183,184,186,187,189,191,193,195,197,199,201,202,204,205],{"kind":41,"text":42},{"kind":16,"text":182}," keeps the keys in C, and calls ",{"kind":41,"text":46},{"kind":16,"text":185}," to erase the base before it tests them. ",{"kind":41,"text":46},{"kind":16,"text":188},"'s ",{"kind":41,"text":190},"LDIR",{"kind":16,"text":192}," counts BC down to 0, so without its ",{"kind":41,"text":194},"PUSH BC",{"kind":16,"text":196}," and ",{"kind":41,"text":198},"POP BC",{"kind":16,"text":200},", C would be 0 when ",{"kind":41,"text":42},{"kind":16,"text":203}," came to ",{"kind":41,"text":161},{"kind":16,"text":206},", and the base would never move. The routine leaves BC as its caller had it.",{"kind":19,"id":208,"text":209},"the-speed","The speed",{"kind":13,"inlines":211},[212,213,215,217,219,221,223,225,227,229,231,232],{"kind":41,"text":42},{"kind":16,"text":214}," runs once a turn, after ",{"kind":41,"text":216},"WAIT",{"kind":16,"text":218},", so a held arrow moves the base one cell a turn. With no key down it adds 48 T-states to the turn, ",{"kind":41,"text":220},"CALL",{"kind":16,"text":222}," 17, ",{"kind":41,"text":224},"LD A,(3840H)",{"kind":16,"text":226}," 13, ",{"kind":41,"text":228},"AND",{"kind":16,"text":230}," 7 and ",{"kind":41,"text":122},{"kind":16,"text":233}," 11, for 133,233 in all; Fugløy runs the Model III at 2.03 MHz, so that is about 66 ms, and the base crosses the screen at about 15 cells a second. Moving costs a few hundred T-states more, too few to see.",{"kind":19,"id":235,"text":236},"keys-go-to-the-screen-not-the-editor","Keys go to the screen, not the editor",{"kind":13,"inlines":238},[239],{"kind":16,"text":240},"Click the TRS-80's screen before you press the arrows, so that it has the keyboard.",{"kind":19,"id":242,"text":243},"on-the-model-i","On the Model I",{"kind":13,"inlines":245},[246],{"kind":16,"text":247},"The Model I has the same keyboard row and the same screen, so the program runs unchanged. Fugløy runs its Z80 at 1.77 MHz, so a turn lasts about 75 ms there and the base moves about 13 cells a second.",[249,260],{"kind":13,"inlines":250},[251,253,255,256,258],{"kind":16,"text":252},"Change ",{"kind":41,"text":254},"CP 61",{"kind":16,"text":104},{"kind":41,"text":257},"CP 40",{"kind":16,"text":259}," and press Run ▶: the right edge is now column 40, and the base stops there, short of the edge, though nothing on the screen marks the spot.",{"kind":13,"inlines":261},[262,264,266,268,270],{"kind":16,"text":263},"Then put it back, and take out the two lines that erase the base, ",{"kind":41,"text":265},"LD HL,BLANK",{"kind":16,"text":267}," and the ",{"kind":41,"text":269},"CALL DRAWBASE",{"kind":16,"text":271}," after it, and run it again. The base still moves, but each move leaves one wing behind, and a held arrow draws a trail of them along the row.",null,[274,278,282,286],{"source":275,"page":276,"about":277},"m3-trm","14","the Model III's keyboard is memory at 3800H-3BFFH, and its screen at 3C00H",{"source":279,"page":280,"about":281},"m1-trh","12","the Model I's keyboard is memory from 3800H, and its screen at 3C00H",{"source":283,"page":284,"about":285},"decker","64","the keyboard's rows are read at 3801H to 3840H, one address a row",{"source":287,"page":288,"about":285},"paay","26","; Build Space Invaders, chapter 3: the arrow keys move the base. Chapter 2's\n; base on row 15, and each turn of the game loop now calls MOVEBASE, which\n; reads the left and right arrows, bits 5 and 6 of the keyboard row at\n; 3840H, and with one down erases the base, moves BASEX a column, and draws\n; the base again; at the screen's edges it stays where it is.\n\n        ORG     7000H           ; the program lives at 7000H, in free memory\n\n; WAIT: a counted delay, 5,120 passes of 26 T-states, about 66 ms a turn at\n; 2.03 MHz. The routines come first, and the game itself after them, from\n; START, where END START says the program begins.\nWAIT:   PUSH    BC              ; save BC, which the loop uses\n        LD      BC,1400H        ; 1400H is 5,120 passes of 26 T-states\nDELAY:  DEC     BC\n        LD      A,B\n        OR      C\n        JR      NZ,DELAY\n        POP     BC              ; BC as the caller left it\n        RET\n\n; DRAWBASE: copy the three bytes HL points at to the base's place on row 15,\n; 3FC0H plus BASEX. BC is kept on the stack; A, DE and HL are not.\nDRAWBASE:\n        PUSH    BC              ; save BC, which LDIR counts down\n        LD      A,(BASEX)       ; the base's column ...\n        ADD     A,0C0H          ; ... plus 3FC0H, row 15: the base's left cell\n        LD      E,A\n        LD      D,3FH\n        LD      BC,3            ; three bytes\n        LDIR                    ; from (HL) to (DE), one byte at a time\n        POP     BC              ; BC as the caller left it\n        RET\n\n; MOVEBASE: with the left or right arrow down, erase the base, move it a\n; column, and draw it again. Columns 0 and 61 are the edges: there it stays.\nMOVEBASE:\n        LD      A,(3840H)       ; the arrows' row: bit 5 left, 6 right\n        AND     60H             ; keep those two bits (0110 0000)\n        RET     Z               ; neither is down: nothing to do\n        LD      C,A             ; keep the keys in C, so A is free\n        LD      HL,BLANK        ; erase the base where it is\n        CALL    DRAWBASE\n        LD      A,(BASEX)       ; the base's column, from memory\n        BIT     5,C             ; left?\n        JR      Z,NOTLT\n        CP      0               ; column 0, the left edge: stay\n        JR      Z,NOTLT\n        DEC     A\nNOTLT:\n        BIT     6,C             ; right?\n        JR      Z,NOTRT\n        CP      61              ; column 61, the right edge for three cells: stay\n        JR      Z,NOTRT\n        INC     A\nNOTRT:\n        LD      (BASEX),A       ; the new column, back to memory\n        LD      HL,BASE         ; draw the base there\n        CALL    DRAWBASE\n        RET\n\nSTART:  LD      HL,3C00H        ; HL points at the top-left cell\n        LD      BC,400H         ; BC counts the cells: 400H is 1024\nCLEAR:  LD      (HL),20H        ; a space: the cell is blank\n        INC     HL              ; on to the next cell\n        DEC     BC              ; one cell fewer to go (DEC BC sets no flags ...)\n        LD      A,B             ; ... so test BC by hand: copy B into A\n        OR      C               ; and OR in C: zero only when B and C both are\n        JR      NZ,CLEAR        ; not zero yet: clear the next cell\n        LD      HL,BASE         ; draw the base where BASEX says\n        CALL    DRAWBASE\n\n; The game loop: one turn of the game, then round again. A game's turn\n; reads the keys, moves things and draws them; this one moves the base.\nLOOP:   CALL    WAIT            ; the turn's pause, so the game runs at a steady speed\n        CALL    MOVEBASE        ; the base moves if an arrow is down\n        JR      LOOP            ; and round again, for ever\n\n; The game's data: below the loop, where the processor never runs into it.\nBASE:   DB      0BCH,0BFH,0BCH  ; the base: a wing, a block, a wing\nBLANK:  DB      '   '           ; three spaces, to erase it\nBASEX:  DB      30              ; the base's column, 0 to 61\n\n        END     START           ; the program starts at START\n","; Build Space Invaders, chapter 2: the base on the bottom row. Chapter 1's\n; blank screen and game loop, and before the loop starts, the player's base\n; is drawn on row 15: three cells, copied to the screen by a routine,\n; DRAWBASE, at the column a byte of memory, BASEX, holds. The loop still\n; only waits; the next chapter moves the base.\n\n        ORG     7000H           ; the program lives at 7000H, in free memory\n\n; WAIT: a counted delay, 5,120 passes of 26 T-states, about 66 ms a turn at\n; 2.03 MHz. The routines come first, and the game itself after them, from\n; START, where END START says the program begins.\nWAIT:   PUSH    BC              ; save BC, which the loop uses\n        LD      BC,1400H        ; 1400H is 5,120 passes of 26 T-states\nDELAY:  DEC     BC\n        LD      A,B\n        OR      C\n        JR      NZ,DELAY\n        POP     BC              ; BC as the caller left it\n        RET\n\n; DRAWBASE: copy the three bytes HL points at to the base's place on row 15,\n; 3FC0H plus BASEX. BC is kept on the stack; A, DE and HL are not.\nDRAWBASE:\n        PUSH    BC              ; save BC, which LDIR counts down\n        LD      A,(BASEX)       ; the base's column ...\n        ADD     A,0C0H          ; ... plus 3FC0H, row 15: the base's left cell\n        LD      E,A\n        LD      D,3FH\n        LD      BC,3            ; three bytes\n        LDIR                    ; from (HL) to (DE), one byte at a time\n        POP     BC              ; BC as the caller left it\n        RET\n\nSTART:  LD      HL,3C00H        ; HL points at the top-left cell\n        LD      BC,400H         ; BC counts the cells: 400H is 1024\nCLEAR:  LD      (HL),20H        ; a space: the cell is blank\n        INC     HL              ; on to the next cell\n        DEC     BC              ; one cell fewer to go (DEC BC sets no flags ...)\n        LD      A,B             ; ... so test BC by hand: copy B into A\n        OR      C               ; and OR in C: zero only when B and C both are\n        JR      NZ,CLEAR        ; not zero yet: clear the next cell\n        LD      HL,BASE         ; draw the base where BASEX says\n        CALL    DRAWBASE\n\n; The game loop: one turn of the game, then round again. A game's turn\n; reads the keys, moves things and draws them; this one only waits.\nLOOP:   CALL    WAIT            ; the turn's pause, so the game runs at a steady speed\n        JR      LOOP            ; and round again, for ever\n\n; The game's data: below the loop, where the processor never runs into it.\nBASE:   DB      0BCH,0BFH,0BCH  ; the base: a wing, a block, a wing\nBASEX:  DB      30              ; the base's column, 0 to 61\n\n        END     START           ; the program starts at START\n",1792464470932]