Advertisement
Guest User

Untitled

a guest
Mar 1st, 2019
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. include "hardware.inc"
  2. include "header.inc"
  3.  
  4.  
  5. section "queue variables", WRAM0
  6. QUEUE: ds 256 ;make the queue 256 large so it wraps itself using overflow
  7. rHEAD: ds 1
  8. rTAIL: ds 1
  9. rSIZE: ds 1 ;amount of data in the queue (the head will keep filling up the queue even if it's full so I need to keep track of the size)
  10.  
  11. section "screen variables", WRAM0
  12. rSCREEN_X: ds 1
  13. rCURRENT_LINE_ADDR: ds 2 ;needs to be 2 bytes because I'm gonna store an address
  14.  
  15. section "serial interrupt", ROM0[$0058]
  16.     jp serial_interrupt
  17.  
  18. section "vblank interrupt", ROM0[$0040]
  19.     jp vblank_interrupt
  20.  
  21.  
  22. section "main", ROM0[$0150] ;NEED TO PUT THIS IN THE RIGHT SPOT (after header) otherwise it'll try to put it between the interrupts and the header
  23.  
  24. main:
  25.  
  26.     di
  27.     call init_display
  28.     call init_serial
  29.     ld a, 0
  30.     ld [rIF], a ;CLEAR INTERRUPT FLAGS!!
  31.     ei
  32. .loop
  33.     halt ;everything's going to happen in vblank and serial interrupts
  34. jr .loop
  35.  
  36.  
  37. init_serial:
  38.  
  39.     push af
  40.     push hl
  41.  
  42.     ld a, %10000000 ;external serial clock, normal speed, SET THE BEGIN TRANSFER BIT SO I CAN RECIEVE DATA (begin transfer bit really just means "when the serial clock ticks, latch/send data")
  43.     ld [rSC], a
  44.  
  45.     ld a, 0
  46.     ld [rHEAD], a
  47.     ld [rTAIL], a
  48.     ld [rSIZE], a ;clear head, tail, and size
  49.  
  50.     ld hl, rIE
  51.     set 3, [hl] ;enable serial interrupt
  52.  
  53.     pop hl
  54.     pop af
  55. ret
  56.  
  57.  
  58. init_display:
  59.  
  60.     push af
  61.     push hl
  62.     push bc
  63.     push de
  64.  
  65. .wait_v_blank
  66.     ld a, [rLY]
  67.     cp 144 ; Check if the LCD is past VBlank
  68.     jr c, .wait_v_blank
  69.  
  70.     ld hl, $9000 ;load font data into vram
  71.     ld de, font_tiles ;start of font data
  72.     ld bc, font_tiles_end - font_tiles ;amount of font data (could have gone without this but then it would be a little more annoying to tell when count was 0)
  73. .copy_font
  74.     ld a, [de] ; nab a byte of the font
  75.     ld [hli], a ; put it in vram, incrementing hl
  76.     inc de ; Move to next byte
  77.     dec bc ; Decrement remaining byte count
  78.     ld a, b ; Check if count is 0
  79.     or c
  80.     jr nz, .copy_font
  81.  
  82.     ld a, %11100100
  83.     ld [rBGP], a ;set pallette
  84.  
  85.     ld a, 0
  86.     ld [rSCY], a
  87.     ld [rSCX], a ;scroll window x and y to 0
  88.  
  89.     ld hl, rIE
  90.     set 0, [hl] ;enable vblank interrupt
  91.  
  92.     ld a, %10000001
  93.     ld [rLCDC], a ;turn lcd back on, put it in the proper mode
  94.  
  95.     pop de
  96.     pop bc
  97.     pop hl
  98.     pop af
  99. ret
  100.  
  101.  
  102. serial_interrupt:
  103.  
  104.     push af
  105.     push bc
  106.     push de
  107.     push hl
  108.  
  109.     ld a, [rSB] ;get the recieved serial data
  110.     ld d, a ;save data for later
  111.     ld a, [rHEAD]
  112.     ld c, a ;save head for later
  113.     ld hl, QUEUE
  114.     ld b, 0 ;so I can add bc to hl and get the address to put the data into
  115.     add hl, bc ;set hl to QUEUE[HEAD] (the location we want to put the data)
  116.     ld [hl], d ;load data into the queue
  117.  
  118.     inc a ;increment the head
  119.     ld [rHEAD], a
  120.  
  121.     ld hl, rSIZE
  122.     ld a, [hl] ;I could just do ld a [rSIZE] but I want to use hl agian later so
  123.     ld b, 255
  124.     cp b
  125.     jr z, .return
  126.     inc [hl] ;increment the size of the queue if it's not 255
  127.  
  128. .return
  129.     ld hl, rSC
  130.     set 7, [hl] ;BEGIN SERIAL TRANSFER AGIAN so that when the external clock ticks I recieve more data
  131.  
  132.     pop hl
  133.     pop de
  134.     pop bc
  135.     pop af
  136. reti
  137.  
  138.  
  139. ;@return CURRENT_LINE_ADDR in hl
  140. get_current_line_addr:
  141.  
  142.     push af
  143.  
  144.     ld hl, rCURRENT_LINE_ADDR
  145.     ld a, [hl]
  146.     inc hl ;go to 2nd byte of rCURRENT_LINE_ADDRESS
  147.     ld l, [hl] ;set low nybble of line address
  148.     ld h, a ;set high nybble of line address
  149.  
  150.     pop af
  151. ret
  152.  
  153.  
  154. vblank_interrupt:
  155.  
  156.     push af
  157.     push bc
  158.     push de
  159.     push hl
  160.     ie ;SO THAT YOU CAN GET SERIALS IN THE MIDDLE OF THIS
  161.  
  162.     ld a, [rSCREEN_X] ;get screen_x for later use
  163.     ld c, a ;store in C so I can later set B to 0 and add hl, bc
  164.  
  165. .draw_loop
  166.     ld a, [rSIZE] ;check how much data is in the queue
  167.     cp 0
  168.     jr z, .return ;stop looping if there's no data left to draw
  169.  
  170.     ld hl, QUEUE
  171.     ld a, [rTAIL]
  172.     ld d, 0 ;set d to 0 so I can add hl, e
  173.     ld e, a
  174.     add hl, de ;hl = QUEUE[rTAIL] (theres no add de, hl opcode sadly)
  175.     ld d, [hl] ;get current byte of data
  176.  
  177.     call get_current_line_addr ;hl = CURRENT_LINE_ADDRESS
  178.  
  179.     ld b, 0
  180.     add hl, bc ;hl = TILEMAP[CURRENT_LINE_ADDRESS + SCREEN_X]
  181.     ld [hl], d ;finally, load the current data byte into the tilemap
  182.  
  183.     ld a, [rSTAT]
  184.     ld b, %00000011 ;bit mask to get bottom 2 bits out of a
  185.     and a, b
  186.     cp 1 ;check if bottom 2 bits of lcdc STAT register are 1
  187.     jr nz, .return ;if it's not currently vblank then don't update anything (since this means previous instructions may have been done outside of vblank)
  188.  
  189.     ld hl, rSIZE ;decrease queue size
  190.     dec [hl] ;I DONT THINK THIS IS UNSAFE BUT YOU MIGHT WANNA MAKE SURE (can an interrupt occur in the middle of a multi cycle instruction?), ALSO KEEP IN MIND THAT THIS IS THE ONLY FUNC THAT DECREASES IT SO IT CAN'T GO BELOW 0 BY ACCIDENT
  191.  
  192.     ld hl, rTAIL
  193.     inc [hl] ;move tail forward
  194.    
  195.     inc c ;increase the tile number
  196.     ld a, c
  197.     cp 20 ;check if tile number is larger than 20
  198.     jr c, .draw_loop ;if tilenum - 20 < 0 we don't need to update the line address. otherwise, we do
  199.  
  200.     ld c, 0 ;set SCREEN_X to 0 since we're going to the beginning of the next line on the screen
  201.     call get_current_line_addr ;hl = CURRENT_LINE_ADDR
  202.     ld de, 32
  203.     add hl, de ;CURRENT_LINE_ADDR += 32 (go to the next line on the screen)
  204.    
  205.     ;CHECK IF NEXT LINE IS OUT OF TILEMAP, IF IT IS THEN RESET CURRENT_LINE_ADDR TO THE START OF THE TILEMAP
  206.    
  207.     ;THINK ABOUT 256 QUEUE THING (SIZE CAN ONLY BE 255 SO CAN I REALLY JUST LET IT WRAP VIA OVERFLOW?)
  208.     ;THINK ABOUT WHETHER I NEED TO BOTHER GETTING SCREEN_X AND KEEPING IT IN A REGISTER (and if not bothering to do that even changes anything)
  209.     ;FIGURE OUT IF AN INTERRUPT CAN HAPPEN IN A MULTI CYCLE INSTRUCTION
  210.  
  211.     jr .draw_loop
  212.  
  213. .return
  214.     pop af
  215.     pop bc
  216.     pop de
  217.     pop hl
  218. ret ;NO RETI BECAUSE NESTED INTERRUPTS
  219.  
  220.  
  221. font_tiles
  222.     incbin "C:\\Users\\Wakydawgster\\Documents\\Programmable Memes\\Assembly SLUDGE\\Gameboy Games\\Serial recv\\font.chr"
  223. font_tiles_end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement