diff --git a/Contralto/AltoSystem.cs b/Contralto/AltoSystem.cs index 3b61850..c64c037 100644 --- a/Contralto/AltoSystem.cs +++ b/Contralto/AltoSystem.cs @@ -41,6 +41,9 @@ namespace Contralto { _cpu.Reset(); _memBus.Reset(); + _mem.Reset(); + ALU.Reset(); + Shifter.Reset(); _diskController.Reset(); } diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs index 75b6bca..6966b28 100644 --- a/Contralto/CPU/CPU.cs +++ b/Contralto/CPU/CPU.cs @@ -80,6 +80,7 @@ namespace Contralto.CPU get { return _aluC0; } } + public void Reset() { // Reset registers diff --git a/Contralto/CPU/Shifter.cs b/Contralto/CPU/Shifter.cs index b07454b..3046717 100644 --- a/Contralto/CPU/Shifter.cs +++ b/Contralto/CPU/Shifter.cs @@ -26,11 +26,18 @@ namespace Contralto.CPU public static class Shifter { static Shifter() + { + Reset(); + } + + public static void Reset() { _op = ShifterOp.Invalid; _count = 0; _output = 0; _magic = false; + _dns = false; + _dnsCarry = 0; } /// @@ -71,6 +78,12 @@ namespace Contralto.CPU /// public static void SetDNS(bool dns, int carry) { + // Sanity check + if (carry != 0 && carry != 1) + { + throw new InvalidOperationException("carry can only be 0 or 1."); + } + _dns = dns; _dnsCarry = carry; } @@ -109,7 +122,16 @@ namespace Contralto.CPU } else if (_dns) { - throw new NotImplementedException("DNS LSH 1"); + // + // "Rotate the 17 input bits left by one bit. This has the effect of rotating + // bit 0 left into the carry position and the carry bit into bit 15." + // + + // Put input carry into bit 15. + _output = (ushort)(_output | _dnsCarry); + + // update carry + _dnsCarry = ((input & 0x8000) >> 15); } break; @@ -124,7 +146,16 @@ namespace Contralto.CPU } else if (_dns) { - throw new NotImplementedException("DNS RSH 1"); + // + // "Rotate the 17 bits right by one bit. Bit 15 is rotated into the carry position + // and the carry bit into bit 0." + // + + // Put input carry into bit 0. + _output |= (ushort)(_output | (_dnsCarry << 15)); + + // update carry + _dnsCarry = input & 0x1; } break; @@ -138,8 +169,11 @@ namespace Contralto.CPU } if (_dns) - { - throw new NotImplementedException("DNS LCY"); + { + // + // "Swap the 8-bit halves of the 16-bit result. The carry is not affected." + // + _output = (ushort)(((input & 0xff00) >> 8) | ((input & 0x00ff) << 8)); } break; diff --git a/Contralto/CPU/Tasks/DiskTask.cs b/Contralto/CPU/Tasks/DiskTask.cs index 4e98c4a..7d695b2 100644 --- a/Contralto/CPU/Tasks/DiskTask.cs +++ b/Contralto/CPU/Tasks/DiskTask.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Contralto.Memory; +using Contralto.Logging; namespace Contralto.CPU { @@ -61,6 +62,7 @@ namespace Contralto.CPU { case DiskF1.LoadKDATA: // "The KDATA register is loaded from BUS[0-15]." + Log.Write(LogComponent.DiskController, "KDATA loaded with {0}", OctalHelpers.ToOctal(_busData)); _cpu._system.DiskController.KDATA = _busData; break; @@ -69,6 +71,7 @@ namespace Contralto.CPU // in addition, it causes the head address bit to be loaded from KDATA[13]." // (the latter is done by DiskController) _cpu._system.DiskController.KADR = (ushort)((_busData & 0xfe) >> 1); + Log.Write(LogComponent.DiskController, "KADR bus data is {0}", OctalHelpers.ToOctal(_busData)); break; case DiskF1.LoadKCOMM: @@ -173,6 +176,10 @@ namespace Contralto.CPU // "NEXT <- NEXT OR (IF disk not ready to accept command THEN 1 ELSE 0) // for now, always zero (not sure when this would be 1 yet) _nextModifier |= GetInitModifier(instruction); + if (!_cpu._system.DiskController.Ready) + { + _nextModifier |= 1; + } break; default: diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs index 700c326..65c310d 100644 --- a/Contralto/CPU/Tasks/EmulatorTask.cs +++ b/Contralto/CPU/Tasks/EmulatorTask.cs @@ -283,7 +283,7 @@ namespace Contralto.CPU case 0x500: case 0x600: // NEG, INC, ADC, SUB, ADD, AND - invert the carry bit - if (ALU.Carry != 0) + if (_cpu._aluC0 != 0) { carry = (~carry) & 0x1; } diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs index 27a4e6b..73a9b3f 100644 --- a/Contralto/CPU/Tasks/Task.cs +++ b/Contralto/CPU/Tasks/Task.cs @@ -339,13 +339,19 @@ namespace Contralto.CPU break; } + + // We always do the shifter operation; DNS may need its output. + // + Shifter.DoOperation(_cpu._l, _cpu._t); + // // Write back to registers: // - // Do writeback to selected R register from shifter output + // Do writeback to selected R register from shifter output. + // if (_loadR) - { - _cpu._r[_rSelect] = Shifter.DoOperation(_cpu._l, _cpu._t); + { + _cpu._r[_rSelect] = Shifter.Output; } // Do writeback to selected R register from M diff --git a/Contralto/Debugger.cs b/Contralto/Debugger.cs index 2362ccb..ca50a93 100644 --- a/Contralto/Debugger.cs +++ b/Contralto/Debugger.cs @@ -96,6 +96,8 @@ namespace Contralto _otherRegs.Rows[2].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.M, 6); _otherRegs.Rows[3].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.IR, 6); _otherRegs.Rows[4].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.ALUC0, 1); + //_otherRegs.Rows[4].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.Carry, 1); + //_otherRegs.Rows[4].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.Skip, 1); _otherRegs.Rows[5].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.MAR, 6); _otherRegs.Rows[6].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.MD, 6); _otherRegs.Rows[7].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.Cycle & 0x3f, 2); @@ -183,9 +185,11 @@ namespace Contralto _otherRegs.Rows.Add("M", "0"); _otherRegs.Rows.Add("IR", "0"); _otherRegs.Rows.Add("ALUC0", "0"); + //_otherRegs.Rows.Add("CARRY", "0"); + //_otherRegs.Rows.Add("SKIP", "0"); _otherRegs.Rows.Add("MAR", "0"); _otherRegs.Rows.Add("MD", "0"); - _otherRegs.Rows.Add("MCycle", "0"); + _otherRegs.Rows.Add("MCycle", "0"); _diskData.Rows.Add("Cycles", "0"); _diskData.Rows.Add("Cylinder", "0"); @@ -492,6 +496,8 @@ namespace Contralto private void OnStepButtonClicked(object sender, EventArgs e) { + StopExecThread(); + SetExecutionState(ExecutionState.SingleStep); ExecuteStep(); SetExecutionState(ExecutionState.Stopped); @@ -499,6 +505,7 @@ namespace Contralto private void OnAutoStepButtonClicked(object sender, EventArgs e) { + StopExecThread(); // // Continuously step (and update the UI) // until the "Stop" button is pressed or something bad happens. @@ -510,6 +517,7 @@ namespace Contralto private void RunButton_Click(object sender, EventArgs e) { + StopExecThread(); // // Continuously execute, but do not update UI // until the "Stop" button is pressed or something bad happens. @@ -524,6 +532,7 @@ namespace Contralto private void RunToNextTaskButton_Click(object sender, EventArgs e) { + StopExecThread(); // // Continuously execute until the next task switch but do not update UI // until the "Stop" button is pressed or something bad happens. @@ -546,6 +555,8 @@ namespace Contralto /// private void NovaStep_Click(object sender, EventArgs e) { + StopExecThread(); + { _execThread = new Thread(new System.Threading.ParameterizedThreadStart(ExecuteProc)); _execThread.Start(ExecutionType.NextNovaInstruction); @@ -554,6 +565,27 @@ namespace Contralto } private void OnStopButtonClicked(object sender, EventArgs e) + { + StopExecThread(); + Refresh(); + } + + + private void ResetButton_Click(object sender, EventArgs e) + { + StopExecThread(); + _system.Reset(); + Refresh(); + } + + private void ExecuteStep() + { + StopExecThread(); + _system.SingleStep(); + Refresh(); + } + + private void StopExecThread() { if (_execThread != null && _execThread.IsAlive) @@ -570,17 +602,6 @@ namespace Contralto SetExecutionState(ExecutionState.Stopped); } - private void ResetButton_Click(object sender, EventArgs e) - { - _system.Reset(); - } - - private void ExecuteStep() - { - _system.SingleStep(); - Refresh(); - } - private void ExecuteProc(object param) { ExecutionType execType = (ExecutionType)param; diff --git a/Contralto/Disassembly/boot block disassembly.txt b/Contralto/Disassembly/boot block disassembly.txt new file mode 100644 index 0000000..7890cd4 --- /dev/null +++ b/Contralto/Disassembly/boot block disassembly.txt @@ -0,0 +1,329 @@ +000:000000 - JMP 000 +001:000345 - JMP 345 ; Entrypoint + +002:000354 - JMP 354 ; Unused (version info, overwritten by disk status by microcode. +003:000403 - JMP .+3 ;(6) ; Ditto +004:120064 - COMC 1,0,SZR ; Build date +005:064330 - NIOP 1,30 + + +006:004415 - JSR .+15 ;(23) ; JSR to zero-length routine at 23; side effect is loading 24 into AC3 (starting offset of data storage) +007:171000 - MOV 3,2 ; copy address 24 into AC2 +010:020410 - LDA 0,.+10 ;(20) ; Load AC0 with 44120 ; disk command (command seal, check header, check label, read data, xfer on, drive 0) +011:024411 - LDA 1,.+11 ;(22) ; Load AC1 with 402 ; address ? +012:004540 - JSR .+140 ;(152) ; jump to subroutine at 152; copy label from 402 to 40 and 62. +013:020406 - LDA 0,.+6 ;(21) ; AC0 gets 400 +014:041007 - STA 0,AC2+7 ; store 400 at 33 +015:004210 - JSR 210 ; jump to subroutine at 210; +016:064401 - DIA 1,1 ; we die here; this is a JSRII instruction which indirects to 0... assume this should actually start real code + +; data ? +017:176776 - SUBSC# 3,3,SEZ + +; data +020:044120 - STA 1,120 +021:000400 - JMP .+0 ;(21) +022:000402 - JMP .+2 ;(24) + +023:005400 - JSR AC3+0 ; Return from zero-length routine + +; Appear to be used as pointers to DCBs at 26 and 50; swapped by routine at 112 +024:176217 - ADCR# 3,3,SBN +025:176175 - ADCLC# 3,3,SNR + +; beginning of first DCB +026:176217 - ADCR# 3,3,SBN ; Pointer to next DCB +027:027400 - LDA@ 1,AC3+0 ; Disk Status +030:044130 - STA 1,130 ; Disk command +031:176205 - ADCR 3,3,SNR ; Header address +032:176207 - ADCR 3,3,SBN ; Label address +033:175550 - INCLO# 3,3 ; Data address (gets 400 (STA at 14)) +034:000000 - JMP 0 ; non-error interrupt mask +035:000000 - JMP 0 ; error interrupt mask +036:000000 - JMP 0 ; reserved +037:000000 - JMP 0 ; disk address + +; 1st copy of label block at 402 starts here +040:130374 - COMSC# 1,2,SZR ; 000400 - disk address (?) +041:000000 - JMP 0 ; 120374 - previous disk address +042:000000 - JMP 0 ; 000000 - blank +043:000000 - JMP 0 ; 001000 - num chars +044:176007 - ADC 3,3,SBN ; 000001 - page number +045:000001 - JMP 1 ; 000001 - version +046:000000 - JMP 0 ; 000000 - sn high +047:000176 - JMP 176 ; 000176 - sn low +; ends here + +; beginning of 2nd DCB +050:000000 - JMP 0 ; Pointer to next DCB +051:000000 - JMP 0 ; Disk Status +052:044130 - STA 1,130 ; Disk command +053:176227 - ADCRZ 3,3,SBN ; Header address +054:176231 - ADCRZ# 3,3,SKP ; Label address +055:176150 - ADCLO# 3,3 ; Data address +056:000000 - JMP 0 ; non-error interrupt mask +057:000000 - JMP 0 ; error interrupt mask +060:000000 - JMP 0 ; reserved +061:130374 - COMSC# 1,2,SZR ; disk address + +; 2nd copy of label block at 402 starts here (and magically matches +; what's already there!) +062:000400 - JMP .+0 ;(62) ; 000400 - disk address (?) +063:120374 - COMSC# 1,0,SZR ; 120374 - previous disk address +064:000000 - JMP 0 ; 000000 - blank +065:001000 - JMP AC2+0 ; 001000 - num chars +066:000001 - JMP 1 ; 000001 - page number +067:000001 - JMP 1 ; 000001 - version +070:000000 - JMP 0 ; 000000 - sn high +071:000176 - JMP 176 ; 000176 - sn low +; ends here + +; temp locations used for return addresses, etc. +072:000000 - JMP 0 +073:176016 - ADC# 3,3,SEZ +074:176147 - ADCLO 3,3,SBN +075:176310 - ADCS# 3,3 +076:000536 - JMP .+136 ;(234) + +; subroutine +077:055051 - STA 3,AC2+51 ; save return address +100:035000 - LDA 3,AC2+0 ; AC3 gets 26 +101:021405 - LDA 0,AC3+5 ; AC0 gets 400 from 33 +102:024717 - LDA 1,.+-61 ;(21) ; AC1 gets 400 from 21 +103:123000 - ADD 1,0 ; AC0 gets AC0+AC1 (1000) +104:024404 - LDA 1,.+4 ;(110) ; AC1 gets -1000 (176777) +105:106032 - ADCZ# 0,1,SZC ; Add 1s cmpl of AC0 (176777) and AC1 (no writeback), skip if carry is zero +106:011051 - ISZ AC2+51 ; increment return address +107:003051 - JMP@ AC2+51 ; return to ret address (+1 added if carry is nonzero) + +; data +110:176777 - SUBSC# 3,3,SBN +111:000420 - JMP .+20 ;(131) + +; subroutine; apparently we're too cool to save our return address. +112:021000 - LDA 0,AC2+0 ; swap contents of locations 24 & 25 +113:025001 - LDA 1,AC2+1 +114:045000 - STA 1,AC2+0 +115:041001 - STA 0,AC2+1 +116:001400 - JMP AC3+0 ; return + +; subroutine. +117:055050 - STA 3,AC2+50 ; save ret +120:176460 - SUBC 3,3 ; get zero +121:055046 - STA 3,AC2+46 ; write zero to 72 +122:000551 - JMP .+151 ;(273) ; continue at 273 + +;subroutine +123:055050 - STA 3,AC2+50 ; save return address +124:035000 - LDA 3,AC2+0 ; AC3 gets DCB address (26 or 50) +125:021412 - LDA 0,AC3+12 ; AC0 gets word 0 of label block @ 40 +126:025411 - LDA 1,AC3+11 ; AC1 gets word at 37 (disk address, word 11 of 1st DCB) +127:035001 - LDA 3,AC2+1 ; AC3 gets other DCB address (@25 - 50 or 26) +130:041411 - STA 0,AC3+11 ; write word 0 of label block to 61 +131:045413 - STA 1,AC3+13 ; write zero to 63 +132:102460 - SUBC 0,0 ; AC0 gets 0 +133:041400 - STA 0,AC3+0 ; zero out 50, 51 (pointer to next DCB, disk status) +134:041401 - STA 0,AC3+1 +135:041412 - STA 0,AC3+12 ; zero out 62, 66 (label words) +136:041416 - STA 0,AC3+16 +137:005053 - JSR AC2+53 ; 77 ; do subroutine at 77; this appears to check if loading is done +140:000405 - JMP .+5 ;(145) ; +141:035001 - LDA 3,AC2+1 ; AC3 gets address of 2nd DCB (50 or 26) +142:041405 - STA 0,AC3+5 ; write 0 to DCB data address +143:057000 - STA@ 3,AC2+0 +144:003050 - JMP@ AC2+50 ; return + +; jumped here from 140 +145:004752 - JSR .+-26 ;(117) +146:003047 - JMP@ AC2+47 ; wait, what? 47? return to.... caller of 210, at 16. This is the end of the loader routine. + +; data +147:000521 - JMP .+121 ;(270) ; KBLK address (pointer to first DCB used by disk hardware) + +; data +150:177756 - ANDSO# 3,3,SEZ +151:000377 - JMP 377 + +; subroutine: copy label block from 402 twice, to 40 and 62. Initialize DCBs at 26 and 50. +; on entry: +; AC0 contains disk command +; AC1 contains 402 (label address for sector 0, where microcode boot copied it originally) +; AC2 contains 24 (offset for all data) +; on exit: +; Label record at 402 (8 bytes long) copied to locs 40-47 and 62-71; +; DCB interrupt masks and addresses zeroed out (at 34-37, 56-61) +; loc 25 points to DCB at 50 + +152:055047 - STA 3,AC2+47 ; save return address @ 73 +153:045051 - STA 1,AC2+51 ; write label address to 75 (AC1 loaded with 402 by caller) +154:015051 - DSZ AC2+51 ; decrement address at 75 (401) +155:041004 - STA 0,AC2+4 ; write 44120 to 30 ; DCB commands +156:041026 - STA 0,AC2+26 ; write 44120 to 52 +157:034561 - LDA 3,.+161 ;(340) ; load AC3 with 2 +160:055050 - STA 3,AC2+50 ; write 2 to 74 - loop counter used at 202 +161:157000 - ADD 2,3 ; 24 + 2, result in AC3 +162:055000 - STA 3,AC2+0 ; store 26 at 24 (top of data structure pointed by AC2) + +; top of loop +163:102460 - SUBC 0,0 ; put a zero in AC0 +164:041406 - STA 0,AC3+6 ; zero out values at 34, 35, 36, 37 and 56, 57, 60, 61 (DCB entries) +165:041407 - STA 0,AC3+7 ; +166:041410 - STA 0,AC3+10 +167:041411 - STA 0,AC3+11 +170:024417 - LDA 1,.+17 ;(207) ; AC1 gets 177770 (-10) +171:136400 - SUB 1,3 ; subtract AC3 from AC1, result in AC3 (26 minus -10 = 36) (calculate label offset)? +172:055773 - STA 3,AC3+-5 ; store AC3 in AC3-5 (31) +173:165400 - INC 3,1 ; inc AC3, store in AC1 (37) +174:125400 - INC 1,1 ; Inc AC1 (AC1 now AC3 + 2 = 40) +175:045774 - STA 1,AC3+-4 ; store AC1 at AC3-4 (32) +176:021051 - LDA 0,AC2+51 ; AC0 gets AC2+51 (24+51) ; blt source (label address -1 = 401) +177:034410 - LDA 3,.+10 ;(207) ; AC3 gets 177770 ; blt count (8 words) +200:166000 - ADC 3,1 ; AC1 gets complement of AC1+AC3 ; blt dest (47 or 61) +201:061005 - BLT ; block transfer -- copy label block from 402 to destination. +202:015050 - DSZ AC2+50 ; decrement copy counter at AC2+50 (74), skip next if zero +203:135401 - INC 1,3,SKP ; Increment AC1 (copy destination), stow in AC3, skip next instruction. +204:003047 - JMP@ AC2+47 ; RTS: exit from DSZ at 202, jump to AC2+47 (@73 -- return from subroutine) +205:055001 - STA 3,AC2+1 ; get here from 203; AC3 stored at AC2 + 1 (25 -- end address + 1 of copied label) +206:000755 - JMP .+-23 ;(163) ; loop back to 163... + +207:177770 - ANDSC# 3,3 ; data - BLT word count (complement) + +210:055047 - STA 3,AC2+47 ; save return address +211:004712 - JSR .+-66 ;(123) ; JSR to 123 +212:004700 - JSR .+-100 ;(112) ; JSR to 112 - swap DCBs @ 24,25 + +; loop here; wait for disk +213:035000 - LDA 3,AC2+0 ; AC3 gets current DCB address +214:025412 - LDA 1,AC3+12 ; AC1 gets label data (previous disk address) +215:022732 - LDA@ 0,.+-46 ;(147) ; Load AC0 with contents KBLK (check controller status) +216:101014 - MOV# 0,0,SZR ; if zero (error or idle) then go to 199 +217:000406 - JMP .+6 ;(225) ; not idle, go to 225 +220:021401 - LDA 0,AC3+1 +221:101014 - MOV# 0,0,SZR +222:000406 - JMP .+6 ;(230) +223:056724 - STA@ 3,.+-54 ;(147) +224:000767 - JMP .+-11 ;(213) + +225:125014 - MOV# 1,1,SZR ; we get here when the disk controller is not idle; see if prev. addr is zero +226:000403 - JMP .+3 ;(231) ; not zero, go to 231 +227:000764 - JMP .+-14 ;(213) ; zero, loop at 213. +230:004667 - JSR .+-111 ;(117) +231:004672 - JSR .+-106 ;(123) ; next DCB? +232:004665 - JSR .+-113 ;(117) ; +233:000757 - JMP .+-21 ;(212) + + +234:174400 - NEG 3,3 +235:160000 - COM 3,0 +236:024501 - LDA 1,.+101 ;(337) +237:034711 - LDA 3,.+-67 ;(150) +240:061005 - BLT +241:004416 - JSR .+16 ;(257) + +; data +242:111111 - MOVL# 0,2,SKP +243:000006 - JMP 6 +244:000000 - JMP 0 +245:000015 - JMP 15 +246:000200 - JMP 200 +247:000012 - JMP 12 +250:100022 - COMZ 0,0,SZC +251:000016 - JMP 16 +252:000001 - JMP 1 +253:000000 - JMP 0 +254:100022 - COMZ 0,0,SZC +255:000040 - JMP 40 +256:000001 - JMP 1 + +257:161000 - MOV 3,0 +260:024765 - LDA 1,.+-13 ;(245) +261:034411 - LDA 3,.+11 ;(272) +262:061005 - BLT +263:020757 - LDA 0,.+-21 ;(242) +264:024457 - LDA 1,.+57 ;(343) +265:034663 - LDA 3,.+-115 ;(150) +266:061006 - BLKS +267:020451 - LDA 0,.+51 ;(340) +270:042621 - STA@ 0,.+-157 ;(111) +271:000400 - JMP .+0 ;(271) + +; +272:177764 - ANDSC 3,3,SZR + +; continuation of subroutine at 122 +273:035000 - LDA 3,AC2+0 +274:021401 - LDA 0,AC3+1 +275:101015 - MOV# 0,0,SNR +276:000775 - JMP .+-3 ;(273) +277:024652 - LDA 1,.+-126 ;(151) +300:107405 - AND 0,1,SNR +301:003050 - JMP@ AC2+50 ; return +302:011046 - ISZ AC2+46 +303:025046 - LDA 1,AC2+46 +304:020433 - LDA 0,.+33 ;(337) +305:122532 - SUBLZ# 1,0,SZC +306:001052 - JMP AC2+52 +307:102460 - SUBC 0,0 +310:041401 - STA 0,AC3+1 +311:041410 - STA 0,AC3+10 +312:041412 - STA 0,AC3+12 +313:041413 - STA 0,AC3+13 +314:041414 - STA 0,AC3+14 +315:041415 - STA 0,AC3+15 +316:041416 - STA 0,AC3+16 +317:020417 - LDA 0,.+17 ;(336) +320:107405 - AND 0,1,SNR +321:000403 - JMP .+3 ;(324) +322:056625 - STA@ 3,.+-153 ;(147) +323:000750 - JMP .+-30 ;(273) +324:054421 - STA 3,.+21 ;(345) +325:021411 - LDA 0,AC3+11 +326:024412 - LDA 1,.+12 ;(340) +327:123400 - AND 1,0 +330:125400 - INC 1,1 +331:044413 - STA 1,.+13 ;(344) +332:004770 - JSR .+-10 ;(322) + +; data +333:000000 - JMP 0 +334:000000 - JMP 0 +335:044002 - STA 1,2 +336:000007 - JMP 7 +337:000037 - JMP 37 +340:000002 - JMP 2 +341:000000 - JMP 0 +342:000000 - JMP 0 +343:000061 - JMP 61 +344:000001 - JMP 1 + +345:102000 - ADC 0,0 ; set up first BLT of all memory to reset Parity +346:024110 - LDA 1,110 +347:134000 - COM 1,3 +350:061005 - BLT ; do BLT +351:056111 - STA@ 3,111 ; write R3 to 420, reset display list (disable display) +352:000003 - JMP 3 ; continue @3 + +353:000000 - JMP 0 +354:000000 - JMP 0 +355:000000 - JMP 0 +356:000000 - JMP 0 + +; data +357:040463 - STA 0,.+63 ;(442) +360:044463 - STA 1,.+63 ;(443) +361:054476 - STA 3,.+76 ;(457) +362:004401 - JSR .+1 ;(363) +363:024471 - LDA 1,.+71 ;(454) +364:167000 - ADD 3,1 +365:034470 - LDA 3,.+70 ;(455) +366:020470 - LDA 0,.+70 ;(456) +367:061005 - BLT +370:034466 - LDA 3,.+66 ;(456) +371:021605 - LDA 0,AC3+-173 +372:040452 - STA 0,.+52 ;(444) +373:021665 - LDA 0,AC3+-113 +374:040445 - STA 0,.+45 ;(441) +375:021640 - LDA 0,AC3+-140 +376:101100 - MOVL 0,0 +377:040446 - STA 0,.+46 ;(445) +400:102460 - SUBC 0,0 \ No newline at end of file diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs index 32979f8..3f8f436 100644 --- a/Contralto/IO/DiskController.cs +++ b/Contralto/IO/DiskController.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Contralto.Memory; using System.IO; +using Contralto.Logging; namespace Contralto.IO { @@ -24,10 +25,7 @@ namespace Contralto.IO _pack.Load(fs); - fs.Close(); - - // Wakeup the sector task first thing - _system.CPU.WakeupTask(CPU.TaskType.DiskSector); + fs.Close(); } public ushort KDATA @@ -36,7 +34,10 @@ namespace Contralto.IO { return _kData; } - set { _kData = value; } + set + { + _kData = value; + } } public ushort KADR @@ -53,6 +54,25 @@ namespace Contralto.IO // "0 normally, 1 if the command is to terminate immediately after the correct cylinder // position is reached (before any data is transferred)." _dataXfer = (_kAdr & 0x2) != 0x2; + + Log.Write(LogComponent.DiskController, "KADR set to {0} (Seal {1}, Header {2}, Label {3}, Data {4}, Xfer {5}, Drive {6})", + OctalHelpers.ToOctal(_kAdr), + OctalHelpers.ToOctal((_kAdr & 0xff00) >> 8), + OctalHelpers.ToOctal((_kAdr & 0xc0) >> 6), + OctalHelpers.ToOctal((_kAdr & 0x30) >> 4), + OctalHelpers.ToOctal((_kAdr & 0xc) >> 2), + _dataXfer, + _kAdr & 0x1); + + Log.Write(LogComponent.DiskController, " Disk Address is C/H/S {0}/{1}/{2}, Drive {3} Restore {4}", + (_kData & 0x0ff8) >> 3, + (_kData & 0x4) >> 2, + (_kData & 0xf000) >> 12, + ((_kData & 0x2) >> 1), + (_kData & 0x1)); + + Log.Write(LogComponent.DiskController, " Selected disk is {0}", ((_kData & 0x2) >> 1) ^ (_kAdr & 0x1)); + } } @@ -148,15 +168,27 @@ namespace Contralto.IO get { return _sectorClocks - _elapsedSectorTime; } } + + public bool Ready + { + get + { + // Not ready if we're in the middle of a seek. + return (_kStat & 0x0040) == 0; + } + } + public void Reset() { ClearStatus(); _recNo = 0; _elapsedSectorTime = 0.0; - _cylinder = 0; + _cylinder = _destCylinder = 0; _sector = 0; _head = 0; _kStat = 0; + _kData = 0; + _sendAdr = false; _wdInhib = true; _xferOff = true; @@ -164,8 +196,13 @@ namespace Contralto.IO _wdInit = false; _diskBitCounterEnable = false; + _sectorWordIndex = 0; + _sectorWordTime = 0; InitSector(); + + // Wakeup the sector task first thing + _system.CPU.WakeupTask(CPU.TaskType.DiskSector); } public void Clock() @@ -219,11 +256,15 @@ namespace Contralto.IO _cylinder--; } + Log.Write(LogComponent.DiskController, "Seek progress: cylinder {0} reached.", _cylinder); + // Are we *there* yet? if (_cylinder == _destCylinder) { // clear Seek bit _kStat &= 0xffbf; + + Log.Write(LogComponent.DiskController, "Seek to {0} completed.", _cylinder); } } } @@ -282,6 +323,8 @@ namespace Contralto.IO { throw new InvalidOperationException("STROBE while SENDADR bit of KCOM not 1. Unexpected."); } + + Log.Write(LogComponent.DiskController, "STROBE: Seek initialized."); _destCylinder = (_kData & 0x0ff8) >> 3; @@ -290,6 +333,8 @@ namespace Contralto.IO if (_destCylinder > 202) { _kStat |= 0x0080; + + Log.Write(LogComponent.DiskController, "Seek failed, specified cylinder {0} is out of range.", _destCylinder); } else { @@ -304,6 +349,8 @@ namespace Contralto.IO // And figure out how long this will take. _seekClocks = CalculateSeekTime(); _elapsedSeekTime = 0.0; + + Log.Write(LogComponent.DiskController, "Seek to {0} from {1} commencing. Will take {2} clocks.", _destCylinder, _cylinder, _seekClocks); } } @@ -380,7 +427,8 @@ namespace Contralto.IO if (_wffo || _diskBitCounterEnable) { if (!_xferOff) - { + { + Log.Write(LogComponent.DiskWordTask, "Word {0} read into KDATA", OctalHelpers.ToOctal(diskWord)); _kData = diskWord; } @@ -403,6 +451,7 @@ namespace Contralto.IO if (bWakeup) { + Log.Write(LogComponent.DiskWordTask, "Sector task awoken."); _system.CPU.WakeupTask(CPU.TaskType.DiskWord); } diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs index 7d097bc..86c5d70 100644 --- a/Contralto/Memory/Memory.cs +++ b/Contralto/Memory/Memory.cs @@ -1,4 +1,5 @@ -using System; +using Contralto.Logging; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,6 +10,11 @@ namespace Contralto.Memory public class Memory : IMemoryMappedDevice { public Memory() + { + Reset(); + } + + public void Reset() { _mem = new ushort[0x10000]; } @@ -19,7 +25,8 @@ namespace Contralto.Memory } public void Load(int address, ushort data) - { + { + //Log.Write(LogComponent.DiskWordTask, "Word {0} written to {1}", OctalHelpers.ToOctal(data), OctalHelpers.ToOctal(address)); _mem[address] = data; }