-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathppu.s
More file actions
283 lines (252 loc) · 9.59 KB
/
ppu.s
File metadata and controls
283 lines (252 loc) · 9.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
.list
.title "robots PPU module"
.global start ; make the entry point available to the linker
.global PPU_ModuleSize
.global PPU_ModuleSizeWords
.include "macros.s"
.include "hwdefs.s"
.include "defs.s"
.include "constants.s"
.equiv PPU_ModuleSize, (end - start)
.equiv PPU_ModuleSizeWords, PPU_ModuleSize/2
.=PPU_UserRamStart
start:
MTPS #PR7
MOV #0100000, SP
mov #PPU_INTERRUPT_VECTORS, r0
10$:
mov #interruptHandlerStub, (r0)+
tst (r0)
bnz 10$
; Setting up PPU address space control register:
; 5432109876543210
; Its default value is 0b0000001100000001
; bit 0: if clear, disables ROM chip in the range 0100000..0117777
; which allows to enable RW access to RAM in that range
; when bit 4 is also set
; bits 1-3: used to select ROM cartridge banks
; bit 4: replaces ROM in the range 0100000..0117777 with RAM (see bit 0)
; bit 5: enables write-only access to RAM in the range 0120000..0137777
; bit 6: enables write-only access to RAM in the range 0140000..0157777
; bit 7: enables write-only access to RAM in the range 0160000..0176777
; bit 8: enables PPU Vblank interrupt when clear, disables when set
; bit 9: enables CPU Vblank interrupt when clear, disables when set
;
; WARNING: since there is no way to disable ROM chips in the range
; 0120000..0176777, write-only access to the RAM is the only option.
; **However**, the UKNCBL emulator allows to reading from the RAM as well!
; **Beware** this is **not** how the real hardware behaves!
;-------------------------------------------------------------------------------
.if AUX_SCREEN_LINES_COUNT != 0
CALL clearAuxScreen
.endif
.ifdef COLOR_TILES
call clearScreen
.else
mov #1, @#BITPLANES_MASK_REG
.endif
.include "ppu/sltab_init.s"
mov #0x001, @#PASWCR
;-------------------------------------------------------------------------------
mov #SLTAB, @#0272 ; use our SLTAB
call Puts
mov #vBlankISR, @#0100
; mov #PR0, @#0102 ; PR7 by default
mov #keyboardISR, @#KBINT
; Set the address of the keyboard layout table to the GRAPH (ГРАФ) mode table
; A hack that changes the keyboard layout in the UKNCBTL emulator from QWERTY to JCUKEN
mov #07774, @#07214
mov #PCH0_IN_INT, r0
mov #channel0InISR, (r0)+
; mov #PR0, (r0) ; PR7 by default
tstb @#PCH0_IN_DATA ; read from the channel, just in case
mov #PCH1_IN_INT, r0
mov #channel1InISR, (r0)+
mov #PR0, (r0) ; PR7 by default
bisb #CH1_IN_INT_BIT, @#PCHSIS ; enable channel 1 input interrupt
tstb @#PCH1_IN_DATA ; read from the channel, just in case
mov #Trap4, @#4
tst @#OPL2
tst @#Trap4Detected
bnz opl2_absent
mov #OPL2, r0
mov r0, OPL2_REGA
mov r0, OPL2_REGB
mov r0, OPL2_REGC
opl2_absent:
mov #trap4Handler, @#04
mov #trap10Handler, @#010
mov #trap24Handler, @#024
call ssy_init
MOV @#023166, rseed1 ; set cursor presence counter value as random seed
MTPS #PR0
; inform loader that PPU is ready to receive commands
MOV #CPU_PPUCommandArg, @#PBPADR
CLR @#PBP12D
;-------------------------------------------------------------------------------
Queue_Loop:
MOV @#CommandsQueue_CurrentPosition, R5
CMP R5, #CommandsQueue_Bottom
BEQ Queue_Loop
MTPS #PR7
MOV (R5)+, R1
MOV (R5)+, R0
MOV R5, @#CommandsQueue_CurrentPosition
MTPS #PR0
.ifdef DEBUG
CMP R1, #PPU.LastJMPTableIndex
BHI .
.endif
CALL @CommandsVectors(R1)
BR Queue_Loop
;-------------------------------------------------------------------------------
CommandsVectors:
.word loadDiskFile
.word setPalette ; PPU.SetPalette
.word clearScreen ; PPU.ClearScreen
.word ssy_music_play
.word setupTimerISR
;-------------------------------------------------------------------------------
clearAuxScreen: ;------------------------------------------------------------{{{
.if AUX_SCREEN_LINES_COUNT != 0
MOV #AUX_SCREEN_LINES_COUNT * (4/LINE_SCALE), R1
MOV #DTSOCT,R4
MOV #PBPADR,R5
MOV #AUX_SCREEN_ADDR,(R5)
CLR @#BP01BC ; background color, pixels 0-3
CLR @#BP12BC ; background color, pixels 4-7
push @#BITPLANES_MASK_REG
CLR @#PBPMSK ; write to all bit-planes
100$:
.rept 10
CLR (R4)
INC (R5)
.endr
SOB R1,100$
pop @#BITPLANES_MASK_REG
RETURN
.endif
;----------------------------------------------------------------------------}}}
clearScreen: ;---------------------------------------------------------------{{{
rept_count = 10
mov #MAIN_SCREEN_LINES_COUNT * LINE_WIDTHW / rept_count, r1
mov #DTSOCT, r4
mov #PBPADR, r5
mov #FB / 2, (r5)
clr @#BP01BC ; background color, pixels 0-3
clr @#BP12BC ; background color, pixels 4-7
100$:
.rept rept_count
clr (R4)
inc (R5)
.endr
sob r1,100$
return
;----------------------------------------------------------------------------}}}
.ifdef INCLUDE_AKG_PLAYER ;----------------------------------------------{{{
.endif ;-----------------------------------------------------------------}}}
loadDiskFile: ; -------------------------------------------------------------{{{
mov #vBlankISR.minimal, @#0100
; in: r0 = address of params struct in CPU memory
clc
ror r0 ; prepare the address to be loaded into address register 0177010
mov r0, @#023200 ; store params struct address for firmware subroutine
; firmware subroutine that handles floppy drive
; (it calls programmable timer subroutine which uses value at 07050)
call @#0131176
wait_while_loading:
tstb @#023334 ; check operation status code (params struct copy)
bmi wait_while_loading
bze 10$
; call handleLoadingError
br .
br .
br .
10$:
mov #vBlankISR, @#0100
; call setupTimerISR
1237$: return
;----------------------------------------------------------------------------}}}
setupTimerISR: ; ------------------------------------------------------------{{{
clr @#TIMER_STATE_REG
mov #timerISR, @#TMRINT
; 12-bit value to load into timer counter
; 1 / (3434 * 4e-6) = 72.80139778683751 Hz
mov #3434, @#TIMER_BUFFER_REG
; bit 6: enables timer interrupt
; bits 2,1: define timer period (00: 2 μs, 01: 4 μs, 10: 8 μs, 11: 16 μs)
; bit 0: starts the timer
; 76543210
mov #0b01000011, @#TIMER_STATE_REG
return
timerISR:
tst @#TIMER_CURRENT_VALUE_REG ; reading the register restarts the timer
; counter if it has reached 0
; bnz .-4 ; retry if timer didn't restart
; (some timers are a bit slow)
tst @#TIMER_CURRENT_VALUE_REG
tst @#TIMER_CURRENT_VALUE_REG
push @#PADDR_REG, r0, r1, r2, r3, r4, r5
call ppu_timer_isr
pop r5, r4, r3, r2, r1, r0, @#PADDR_REG
rti
;----------------------------------------------------------------------------}}}
; 16-bit LFSR Random Number Generator (Optimized)
; PDP-11 Assembly
; Seed must be non-zero (e.g., 0xACE1)
; Uses R0 (state) and R1 (preloaded with 0xB400 tap mask)
; Caller must initialize R1 with 0xB400 once
next_random:
.equiv nrseed, .+2
mov #0xACE1, r0
clc ; Clear carry for logical shift (fill high bit with 0)
ror r0 ; Shift R0 right: LSB → Carry, high bit ← 0
bcs xor_step ; If Carry=1 (original LSB was 1), branch to XOR
mov r0, nrseed
return ; Return if Carry=0
xor_step:
mov #0xB400, r1
xor r1, r0 ; Apply feedback using tap mask in R1
mov r0, nrseed
return ; Return
; Generates a 16-bit pseudorandom number using LSFR
; output: R0 - next pseudorandom number
RandomWord:
.equiv rseed1, .+2
mov #0, r0 ; load the current seed value into R0
asl r0 ; double the value in R0
bhi 10$ ; branch if neither a carry nor a zero flags are set
add #39, r0
10$:
mov r0, rseed1 ; store the new seed value back to rseed1
.equiv rseed2, .+2
add #0x9820, r0; add the secondary seed value to R0
mov r0, rseed2 ; store the result back to rseed2
return
subroutineStub:
return
interruptHandlerStub:
br .
nop
nop
PPU_INTERRUPT_VECTORS:
.word 04, 010, 014, 020, 024, 030, 034, 0100
.word 0300, 0304, 0310, 0314, 0320, 0324, 0330, 0334, 0340
.word 0 ; terminator
.include "ppu/channel_0_in_isr.s"
.include "ppu/channel_1_in_isr.s"
.include "ppu/errors_handler.s"
.include "ppu/keyboard_isr.s"
.include "ppu/puts.s"
.include "ppu/set_palette.s"
.include "ppu/trap_4_isr.s"
.include "ppu/v_blank_isr.s"
.include "audio/ppu_audio.s"
CommandsQueue_Top:
.ds 2*16
CommandsQueue_Bottom:
WAKING_UP_STR:
.asciz "Waking up the robots..."
.even
end:
.nolist